source: creddy/generate.c @ 3131b19

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

creddy generate library function

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