-
Notifications
You must be signed in to change notification settings - Fork 1
/
cert.c
137 lines (127 loc) · 3.71 KB
/
cert.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#define _POSIX_C_SOURCE 200809L /* for gmtime_r */
#include <assert.h>
#include "x509cert.h"
#include "inner.h"
static size_t
encode_time(time_t t, unsigned char *buf)
{
static const char dec[] = "0123456789";
struct tm tm;
char str[16];
struct x509cert_item item = {X509CERT_ASN1_GENERALIZEDTIME, 15, str};
int x;
if (buf) {
if (!gmtime_r(&t, &tm))
return 0;
x = tm.tm_year;
str[3] = dec[x % 10], x /= 10;
str[2] = dec[x % 10], x = x / 10 + 19;
str[1] = dec[x % 10], x /= 10;
str[0] = dec[x % 10];
x = tm.tm_mon + 1;
str[5] = dec[x % 10], x /= 10;
str[4] = dec[x % 10];
x = tm.tm_mday;
str[7] = dec[x % 10], x /= 10;
str[6] = dec[x % 10];
x = tm.tm_hour;
str[9] = dec[x % 10], x /= 10;
str[8] = dec[x % 10];
x = tm.tm_min;
str[11] = dec[x % 10], x /= 10;
str[10] = dec[x % 10];
x = tm.tm_sec;
str[13] = dec[x % 10], x /= 10;
str[12] = dec[x % 10];
str[14] = 'Z';
str[15] = '\0';
}
if (t < 2524608000) {
/* use UTCTime for years before 2050 */
item.tag = X509CERT_ASN1_UTCTIME;
item.len -= 2;
item.val = str + 2;
}
return x509cert_encode(&item, buf);
}
/* basicConstraints extension */
static size_t
encode_bc(int ca, unsigned char *buf)
{
static const unsigned char der[] = {
0x30, 0x0c,
0x06, 0x03, 0x55, 0x1d, 0x13,
0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
};
if (buf) {
memcpy(buf, der, sizeof(der));
buf[sizeof(der)] = ca ? 0xff : 0;
}
return sizeof(der) + 1;
}
size_t
x509cert_encode_cert(const struct x509cert_cert *cert, unsigned char *buf)
{
static const unsigned char ver[] = {0xa0, 0x03, 0x02, 0x01, 0x02};
struct x509cert_item item = {X509CERT_ASN1_SEQUENCE};
struct x509cert_item serial;
struct x509cert_item validity = {X509CERT_ASN1_SEQUENCE};
struct x509cert_item optexts = {0xa3};
struct x509cert_item exts = {X509CERT_ASN1_SEQUENCE};
size_t len;
x509cert_uint(&serial, cert->serial, sizeof(cert->serial));
item.len += x509cert_encode(&serial, NULL);
len = x509cert_encode_sign_alg(cert->key_type, cert->hash_id, NULL);
if (len == 0)
return 0;
item.len += len;
item.len += x509cert_encode(&cert->issuer, NULL);
validity.len = encode_time(cert->notbefore, NULL) + encode_time(cert->notafter, NULL);
item.len += x509cert_encode(&validity, NULL);
item.len += x509cert_encode(&cert->req->subject, NULL);
item.len += x509cert_encode_pkey(&cert->req->pkey, NULL);
if (cert->req->alts_len > 0)
exts.len += x509cert_encode_san(cert->req->alts, cert->req->alts_len, NULL);
if (cert->ca)
exts.len += encode_bc(cert->ca, NULL);
if (exts.len > 0) {
item.len += sizeof(ver);
optexts.len = x509cert_encode(&exts, NULL);
item.len += x509cert_encode(&optexts, NULL);
}
len = x509cert_encode(&item, NULL);
if (buf) {
size_t timelen;
unsigned char *pos = buf;
pos += x509cert_encode(&item, pos);
if (exts.len > 0)
pos += x509cert_copy(ver, pos);
pos += x509cert_encode(&serial, pos);
pos += x509cert_encode_sign_alg(cert->key_type, cert->hash_id, pos);
pos += x509cert_encode(&cert->issuer, pos);
pos += x509cert_encode(&validity, pos);
if (!(timelen = encode_time(cert->notbefore, pos)))
return 0;
pos += timelen;
if (!(timelen = encode_time(cert->notafter, pos)))
return 0;
pos += timelen;
pos += x509cert_encode(&cert->req->subject, pos);
pos += x509cert_encode_pkey(&cert->req->pkey, pos);
if (exts.len > 0) {
pos += x509cert_encode(&optexts, pos);
pos += x509cert_encode(&exts, pos);
if (cert->req->alts_len > 0)
pos += x509cert_encode_san(cert->req->alts, cert->req->alts_len, pos);
if (cert->ca)
pos += encode_bc(cert->ca, pos);
}
assert(pos - buf == len);
}
return len;
}
size_t
x509cert_cert_encoder(const struct x509cert_item *item, unsigned char *buf)
{
return x509cert_encode_cert(item->val, buf);
}