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:                                                        &not_before, &not_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>