Annotation of embedaddon/strongswan/src/pki/commands/self.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2009 Martin Willi
3: * Copyright (C) 2015-2019 Andreas Steffen
4: * HSR Hochschule fuer Technik Rapperswil
5: *
6: * This program is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2 of the License, or (at your
9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10: *
11: * This program is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14: * for more details.
15: */
16:
17: #include <time.h>
18: #include <errno.h>
19:
20: #include "pki.h"
21:
22: #include <collections/linked_list.h>
23: #include <credentials/certificates/certificate.h>
24: #include <credentials/certificates/x509.h>
25: #include <selectors/traffic_selector.h>
26: #include <asn1/asn1.h>
27:
28: /**
29: * Free cert policy with OID
30: */
31: static void destroy_cert_policy(x509_cert_policy_t *policy)
32: {
33: free(policy->oid.ptr);
34: free(policy);
35: }
36:
37: /**
38: * Free policy mapping
39: */
40: static void destroy_policy_mapping(x509_policy_mapping_t *mapping)
41: {
42: free(mapping->issuer.ptr);
43: free(mapping->subject.ptr);
44: free(mapping);
45: }
46:
47: /**
48: * Create a self signed certificate.
49: */
50: static int self()
51: {
52: cred_encoding_type_t form = CERT_ASN1_DER;
53: key_type_t type = KEY_ANY;
54: hash_algorithm_t digest = HASH_UNKNOWN;
55: signature_params_t *scheme = NULL;
56: certificate_t *cert = NULL;
57: private_key_t *private = NULL;
58: public_key_t *public = NULL;
59: char *file = NULL, *dn = NULL, *hex = NULL, *error = NULL, *keyid = NULL;
60: identification_t *id = NULL;
61: linked_list_t *san, *ocsp, *permitted, *excluded, *policies, *mappings;
62: linked_list_t *addrblocks;
63: int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT;
64: int inhibit_mapping = X509_NO_CONSTRAINT;
65: int require_explicit = X509_NO_CONSTRAINT;
66: chunk_t serial = chunk_empty;
67: chunk_t encoding = chunk_empty;
68: chunk_t critical_extension_oid = chunk_empty;
69: time_t not_before, not_after, lifetime = 1095 * 24 * 60 * 60;
70: char *datenb = NULL, *datena = NULL, *dateform = NULL;
71: x509_flag_t flags = 0;
72: x509_cert_policy_t *policy = NULL;
73: traffic_selector_t *ts;
74: char *arg;
75: bool pss = lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
76: lib->ns);
77:
78: san = linked_list_create();
79: ocsp = linked_list_create();
80: permitted = linked_list_create();
81: excluded = linked_list_create();
82: policies = linked_list_create();
83: mappings = linked_list_create();
84: addrblocks = linked_list_create();
85:
86: while (TRUE)
87: {
88: switch (command_getopt(&arg))
89: {
90: case 'h':
91: goto usage;
92: case 't':
93: if (streq(arg, "rsa"))
94: {
95: type = KEY_RSA;
96: }
97: else if (streq(arg, "ecdsa"))
98: {
99: type = KEY_ECDSA;
100: }
101: else if (streq(arg, "ed25519"))
102: {
103: type = KEY_ED25519;
104: }
105: else if (streq(arg, "ed448"))
106: {
107: type = KEY_ED448;
108: }
109: else if (streq(arg, "bliss"))
110: {
111: type = KEY_BLISS;
112: }
113: else if (streq(arg, "priv"))
114: {
115: type = KEY_ANY;
116: }
117: else
118: {
119: error = "invalid input type";
120: goto usage;
121: }
122: continue;
123: case 'g':
124: if (!enum_from_name(hash_algorithm_short_names, arg, &digest))
125: {
126: error = "invalid --digest type";
127: goto usage;
128: }
129: continue;
130: case 'R':
131: if (streq(arg, "pss"))
132: {
133: pss = TRUE;
134: }
135: else if (!streq(arg, "pkcs1"))
136: {
137: error = "invalid RSA padding";
138: goto usage;
139: }
140: continue;
141: case 'i':
142: file = arg;
143: continue;
144: case 'x':
145: keyid = arg;
146: continue;
147: case 'd':
148: dn = arg;
149: continue;
150: case 'a':
151: san->insert_last(san, identification_create_from_string(arg));
152: continue;
153: case 'l':
154: lifetime = atoi(arg) * 24 * 60 * 60;
155: if (!lifetime)
156: {
157: error = "invalid --lifetime value";
158: goto usage;
159: }
160: continue;
161: case 'D':
162: dateform = arg;
163: continue;
164: case 'F':
165: datenb = arg;
166: continue;
167: case 'T':
168: datena = arg;
169: continue;
170: case 's':
171: hex = arg;
172: continue;
173: case 'b':
174: flags |= X509_CA;
175: continue;
176: case 'p':
177: pathlen = atoi(arg);
178: continue;
179: case 'B':
180: ts = parse_ts(arg);
181: if (!ts)
182: {
183: error = "invalid addressBlock";
184: goto usage;
185: }
186: addrblocks->insert_last(addrblocks, ts);
187: continue;
188: case 'n':
189: permitted->insert_last(permitted,
190: identification_create_from_string(arg));
191: continue;
192: case 'N':
193: excluded->insert_last(excluded,
194: identification_create_from_string(arg));
195: continue;
196: case 'P':
197: {
198: chunk_t oid;
199:
200: oid = asn1_oid_from_string(arg);
201: if (!oid.len)
202: {
203: error = "--cert-policy OID invalid";
204: goto usage;
205: }
206: INIT(policy,
207: .oid = oid,
208: );
209: policies->insert_last(policies, policy);
210: continue;
211: }
212: case 'C':
213: if (!policy)
214: {
215: error = "--cps-uri must follow a --cert-policy";
216: goto usage;
217: }
218: policy->cps_uri = arg;
219: continue;
220: case 'U':
221: if (!policy)
222: {
223: error = "--user-notice must follow a --cert-policy";
224: goto usage;
225: }
226: policy->unotice_text = arg;
227: continue;
228: case 'M':
229: {
230: char *pos = strchr(arg, ':');
231: x509_policy_mapping_t *mapping;
232: chunk_t subject_oid, issuer_oid;
233:
234: if (pos)
235: {
236: *pos++ = '\0';
237: issuer_oid = asn1_oid_from_string(arg);
238: subject_oid = asn1_oid_from_string(pos);
239: }
240: if (!pos || !issuer_oid.len || !subject_oid.len)
241: {
242: error = "--policy-map OIDs invalid";
243: goto usage;
244: }
245: INIT(mapping,
246: .issuer = issuer_oid,
247: .subject = subject_oid,
248: );
249: mappings->insert_last(mappings, mapping);
250: continue;
251: }
252: case 'E':
253: require_explicit = atoi(arg);
254: continue;
255: case 'H':
256: inhibit_mapping = atoi(arg);
257: continue;
258: case 'A':
259: inhibit_any = atoi(arg);
260: continue;
261: case 'e':
262: if (streq(arg, "serverAuth"))
263: {
264: flags |= X509_SERVER_AUTH;
265: }
266: else if (streq(arg, "clientAuth"))
267: {
268: flags |= X509_CLIENT_AUTH;
269: }
270: else if (streq(arg, "ikeIntermediate"))
271: {
272: flags |= X509_IKE_INTERMEDIATE;
273: }
274: else if (streq(arg, "crlSign"))
275: {
276: flags |= X509_CRL_SIGN;
277: }
278: else if (streq(arg, "ocspSigning"))
279: {
280: flags |= X509_OCSP_SIGNER;
281: }
282: else if (streq(arg, "msSmartcardLogon"))
283: {
284: flags |= X509_MS_SMARTCARD_LOGON;
285: }
286: continue;
287: case 'f':
288: if (!get_form(arg, &form, CRED_CERTIFICATE))
289: {
290: error = "invalid output format";
291: goto usage;
292: }
293: continue;
294: case 'o':
295: ocsp->insert_last(ocsp, arg);
296: continue;
297: case 'X':
298: chunk_free(&critical_extension_oid);
299: critical_extension_oid = asn1_oid_from_string(arg);
300: continue;
301: case EOF:
302: break;
303: default:
304: error = "invalid --self option";
305: goto usage;
306: }
307: break;
308: }
309:
310: if (!dn)
311: {
312: error = "--dn is required";
313: goto usage;
314: }
315: if (!calculate_lifetime(dateform, datenb, datena, lifetime,
316: ¬_before, ¬_after))
317: {
318: error = "invalid --not-before/after datetime";
319: goto usage;
320: }
321: id = identification_create_from_string(dn);
322: if (id->get_type(id) != ID_DER_ASN1_DN)
323: {
324: error = "supplied --dn is not a distinguished name";
325: goto end;
326: }
327: if (file)
328: {
329: private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
330: BUILD_FROM_FILE, file, BUILD_END);
331: }
332: else if (keyid)
333: {
334: chunk_t chunk;
335:
336: chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
337: private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
338: BUILD_PKCS11_KEYID, chunk, BUILD_END);
339: free(chunk.ptr);
340: }
341: else
342: {
343: chunk_t chunk;
344:
345: set_file_mode(stdin, CERT_ASN1_DER);
346: if (!chunk_from_fd(0, &chunk))
347: {
348: fprintf(stderr, "%s: ", strerror(errno));
349: error = "reading private key failed";
350: goto end;
351: }
352: private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
353: BUILD_BLOB, chunk, BUILD_END);
354: free(chunk.ptr);
355: }
356: if (!private)
357: {
358: error = "loading private key failed";
359: goto end;
360: }
361: public = private->get_public_key(private);
362: if (!public)
363: {
364: error = "extracting public key failed";
365: goto end;
366: }
367: if (hex)
368: {
369: serial = chunk_from_hex(chunk_create(hex, strlen(hex)), NULL);
370: }
371: else
372: {
373: rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
374:
375: if (!rng)
376: {
377: error = "no random number generator found";
378: goto end;
379: }
380: if (!rng_allocate_bytes_not_zero(rng, 8, &serial, FALSE))
381: {
382: error = "failed to generate serial number";
383: rng->destroy(rng);
384: goto end;
385: }
386: serial.ptr[0] &= 0x7F;
387: rng->destroy(rng);
388: }
389: scheme = get_signature_scheme(private, digest, pss);
390: if (!scheme)
391: {
392: error = "no signature scheme found";
393: goto end;
394: }
395:
396: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
397: BUILD_SIGNING_KEY, private, BUILD_PUBLIC_KEY, public,
398: BUILD_SUBJECT, id, BUILD_NOT_BEFORE_TIME, not_before,
399: BUILD_NOT_AFTER_TIME, not_after, BUILD_SERIAL, serial,
400: BUILD_SIGNATURE_SCHEME, scheme, BUILD_X509_FLAG, flags,
401: BUILD_PATHLEN, pathlen, BUILD_SUBJECT_ALTNAMES, san,
402: BUILD_ADDRBLOCKS, addrblocks,
403: BUILD_OCSP_ACCESS_LOCATIONS, ocsp,
404: BUILD_PERMITTED_NAME_CONSTRAINTS, permitted,
405: BUILD_EXCLUDED_NAME_CONSTRAINTS, excluded,
406: BUILD_CERTIFICATE_POLICIES, policies,
407: BUILD_POLICY_MAPPINGS, mappings,
408: BUILD_POLICY_REQUIRE_EXPLICIT, require_explicit,
409: BUILD_POLICY_INHIBIT_MAPPING, inhibit_mapping,
410: BUILD_POLICY_INHIBIT_ANY, inhibit_any,
411: BUILD_CRITICAL_EXTENSION, critical_extension_oid,
412: BUILD_END);
413: if (!cert)
414: {
415: error = "generating certificate failed";
416: goto end;
417: }
418: if (!cert->get_encoding(cert, form, &encoding))
419: {
420: error = "encoding certificate failed";
421: goto end;
422: }
423: set_file_mode(stdout, form);
424: if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
425: {
426: error = "writing certificate key failed";
427: goto end;
428: }
429:
430: end:
431: DESTROY_IF(id);
432: DESTROY_IF(cert);
433: DESTROY_IF(public);
434: DESTROY_IF(private);
435: san->destroy_offset(san, offsetof(identification_t, destroy));
436: permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
437: excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
438: addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
439: policies->destroy_function(policies, (void*)destroy_cert_policy);
440: mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
441: ocsp->destroy(ocsp);
442: signature_params_destroy(scheme);
443: free(critical_extension_oid.ptr);
444: free(encoding.ptr);
445: free(serial.ptr);
446:
447: if (error)
448: {
449: fprintf(stderr, "%s\n", error);
450: return 1;
451: }
452: return 0;
453:
454: usage:
455: san->destroy_offset(san, offsetof(identification_t, destroy));
456: permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
457: excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
458: addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
459: policies->destroy_function(policies, (void*)destroy_cert_policy);
460: mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
461: ocsp->destroy(ocsp);
462: free(critical_extension_oid.ptr);
463: return command_usage(error);
464: }
465:
466: /**
467: * Register the command.
468: */
469: static void __attribute__ ((constructor))reg()
470: {
471: command_register((command_t) {
472: self, 's', "self",
473: "create a self signed certificate",
474: {"[--in file|--keyid hex] [--type rsa|ecdsa|ed25519|ed448|bliss|priv]",
475: " --dn distinguished-name [--san subjectAltName]+",
476: "[--lifetime days] [--serial hex] [--ca] [--ocsp uri]+",
477: "[--flag serverAuth|clientAuth|crlSign|ocspSigning|msSmartcardLogon]+",
478: "[--nc-permitted name] [--nc-excluded name]",
479: "[--policy-map issuer-oid:subject-oid]",
480: "[--policy-explicit len] [--policy-inhibit len] [--policy-any len]",
481: "[--cert-policy oid [--cps-uri uri] [--user-notice text]]+",
482: "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
483: "[--rsa-padding pkcs1|pss] [--critical oid]",
484: "[--outform der|pem]"},
485: {
486: {"help", 'h', 0, "show usage information"},
487: {"in", 'i', 1, "private key input file, default: stdin"},
488: {"keyid", 'x', 1, "smartcard or TPM private key object handle"},
489: {"type", 't', 1, "type of input key, default: priv"},
490: {"dn", 'd', 1, "subject and issuer distinguished name"},
491: {"san", 'a', 1, "subjectAltName to include in certificate"},
492: {"lifetime", 'l', 1, "days the certificate is valid, default: 1095"},
493: {"not-before", 'F', 1, "date/time the validity of the cert starts"},
494: {"not-after", 'T', 1, "date/time the validity of the cert ends"},
495: {"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
496: {"serial", 's', 1, "serial number in hex, default: random"},
497: {"ca", 'b', 0, "include CA basicConstraint, default: no"},
498: {"pathlen", 'p', 1, "set path length constraint"},
499: {"addrblock", 'B', 1, "RFC 3779 addrBlock to include"},
500: {"nc-permitted", 'n', 1, "add permitted NameConstraint"},
501: {"nc-excluded", 'N', 1, "add excluded NameConstraint"},
502: {"cert-policy", 'P', 1, "certificatePolicy OID to include"},
503: {"cps-uri", 'C', 1, "Certification Practice statement URI for certificatePolicy"},
504: {"user-notice", 'U', 1, "user notice for certificatePolicy"},
505: {"policy-mapping", 'M', 1, "policyMapping from issuer to subject OID"},
506: {"policy-explicit", 'E', 1, "requireExplicitPolicy constraint"},
507: {"policy-inhibit", 'H', 1, "inhibitPolicyMapping constraint"},
508: {"policy-any", 'A', 1, "inhibitAnyPolicy constraint"},
509: {"flag", 'e', 1, "include extendedKeyUsage flag"},
510: {"ocsp", 'o', 1, "OCSP AuthorityInfoAccess URI to include"},
511: {"digest", 'g', 1, "digest for signature creation, default: key-specific"},
512: {"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"},
513: {"critical", 'X', 1, "critical extension OID to include for test purposes"},
514: {"outform", 'f', 1, "encoding of generated cert, default: der"},
515: }
516: });
517: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>