source: creddy/generate.c @ 5a72d21

abac0-leakabac0-meicompt_changesgec13mei-idmei-rt0-nmei_rt0mei_rt2mei_rt2_fix_1meiyap-rt1meiyap1rt2tvf-new-xml
Last change on this file since 5a72d21 was 085f159, checked in by Mike Ryan <mikeryan@…>, 14 years ago

creddy attribute cert generator

  • Property mode set to 100644
File size: 5.0 KB
Line 
1#include <fcntl.h>
2
3#include <credentials/keys/private_key.h>
4
5#include "creddy.h"
6
7#define KEY_SUFFIX  "_private.der"
8#define CERT_SUFFIX "_ID.pem"
9
10static private_key_t *_generate_key(char *filename);
11static void _generate_cert(char *filename, private_key_t *private, char *cn, int validity);
12
13void generate_main(options_t *opts) {
14    int ret;
15    chunk_t encoding;
16    char *cn = opts->cn, *filename;
17    int cn_len;
18    private_key_t *key;
19
20    if (cn == NULL)
21        usage(opts);
22
23    if (!clean_name(cn)) {
24        printf("Invalid CN: must start with a letter and be alphanumeric\n");
25        usage(opts);
26    }
27    if (opts->validity <= 0) {
28        printf("Validity must be >= 1 day\n");
29        usage(opts);
30    }
31
32    cn_len = strlen(cn);
33
34    // key output filename: "${cn}_private.der"
35    filename = xmalloc(cn_len + sizeof(KEY_SUFFIX));
36    memcpy(filename, cn, cn_len);
37
38    memcpy(filename + cn_len, KEY_SUFFIX, sizeof(KEY_SUFFIX));
39    key = _generate_key(filename);
40
41    // cert filename: ${cn}_ID.pem
42    memcpy(filename +cn_len, CERT_SUFFIX, sizeof(CERT_SUFFIX));
43    _generate_cert(filename, key, cn, opts->validity);
44
45    free(filename);
46    DESTROY_IF(key);
47}
48
49static private_key_t *_generate_key(char *filename) {
50    private_key_t *key;
51    int ret;
52    chunk_t encoding;
53
54    printf("Generating key, this will take a while. Create entropy!\n");
55    printf("    - move the mouse\n");
56    printf("    - generate disk activity (run find)\n");
57
58    // generate the key
59    key = lib->creds->create(
60        lib->creds,
61        CRED_PRIVATE_KEY, KEY_RSA,
62        BUILD_KEY_SIZE, 2048,
63        BUILD_END
64    );
65    if (key == NULL)
66        errx(1, "Key generation failed");
67
68    // get the key encoding
69    ret = key->get_encoding(key, KEY_PRIV_ASN1_DER, &encoding);
70    if (!ret)
71        errx(1, "Couldn't encode private key");
72
73    // write it to a file (with mode 600)
74    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
75    if (fd < 0)
76        err(1, "Couldn't open %s for writing private key", filename);
77
78    ret = write(fd, encoding.ptr, encoding.len);
79    if (ret < encoding.len)
80        errx(1, "Couldn't write all the bytes of the private key");
81
82    close(fd);
83
84    free(encoding.ptr);
85
86    return key;
87}
88
89static char *_create_dn(char *cn) {
90
91#define DN "cn="
92
93    char *dn = xmalloc(sizeof(DN) + strlen(cn));
94    memcpy(dn, DN, sizeof(DN));
95    strcat(dn, cn);
96
97    return dn;
98}
99
100#define BYTES_PER_LINE 64
101
102// thx libstrongswan
103static void _encode_base64(char *filename, chunk_t encoding) {
104    int start;
105
106    chunk_t b64 = chunk_to_base64(encoding, NULL);
107
108    FILE *out = fopen(filename, "w");
109    if (out == NULL)
110        err(1, "couldn't open %s for writing", filename);
111
112    fprintf(out, "-----BEGIN CERTIFICATE-----\n");
113
114    for (start = 0; start < b64.len; start += BYTES_PER_LINE) {
115        int left = b64.len - start;
116        int len = left < BYTES_PER_LINE ? left : BYTES_PER_LINE;
117        fwrite(b64.ptr + start, len, 1, out);
118        fprintf(out, "\n");
119    }
120
121    fprintf(out, "-----END CERTIFICATE-----\n");
122    fclose(out);
123
124    free(b64.ptr);
125}
126
127static void _generate_cert(char *filename, private_key_t *private, char *cn, int validity) {
128    // build the DN
129    char *dn_string = _create_dn(cn);
130    identification_t *id = identification_create_from_string(dn_string);
131    if (id == NULL)
132        errx(1, "couldn't create ID from DN %s", dn_string);
133    free(dn_string);
134
135    // get the public key
136    public_key_t *public = private->get_public_key(private);
137    if (public == NULL)
138        errx(1, "couldn't get public key from private key");
139
140    // create a serial (stolen from strongswan pki)
141    rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
142    if (!rng)
143        errx(1, "no random number generator");
144
145    // random serial
146    chunk_t serial = generate_serial();
147
148    // validity period
149    time_t not_before = time(NULL);
150    time_t not_after = not_before + validity * 24 * 60 * 60;
151
152    // create!
153    certificate_t *cert = lib->creds->create(lib->creds,
154        CRED_CERTIFICATE, CERT_X509,
155        BUILD_SIGNING_KEY, private,
156        BUILD_PUBLIC_KEY, public,
157        BUILD_SUBJECT, id,
158        BUILD_NOT_BEFORE_TIME, not_before,
159        BUILD_NOT_AFTER_TIME, not_after,
160        BUILD_SERIAL, serial,
161        BUILD_DIGEST_ALG, HASH_SHA1,
162        BUILD_X509_FLAG, X509_CA,
163        BUILD_PATHLEN, X509_NO_PATH_LEN_CONSTRAINT,
164        BUILD_END
165    );
166    if (cert == NULL)
167        errx(1, "couldn't build cert :(");
168
169    chunk_t encoding = cert->get_encoding(cert);
170
171    // sigh
172    _encode_base64(filename, encoding);
173
174    DESTROY_IF(id);
175    DESTROY_IF(cert);
176    DESTROY_IF(public);
177    free(encoding.ptr);
178    free(serial.ptr);
179}
180
181chunk_t generate_serial() {
182    chunk_t serial = chunk_empty;
183
184    // create a serial (stolen from strongswan pki)
185    rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
186    if (!rng)
187        errx(1, "no random number generator");
188
189    rng->allocate_bytes(rng, 8, &serial);
190    while (serial.ptr[0] == 0)
191        // don't get leading 0's
192        rng->get_bytes(rng, 1, serial.ptr);
193    rng->destroy(rng);
194
195    return serial;
196}
Note: See TracBrowser for help on using the repository browser.