[BACK]Return to x509.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / openssl

Annotation of src/usr.bin/openssl/x509.c, Revision 1.32

1.32    ! tb          1: /* $OpenBSD: x509.c,v 1.31 2023/03/06 14:32:06 tb Exp $ */
1.1       jsing       2: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
                      3:  * All rights reserved.
                      4:  *
                      5:  * This package is an SSL implementation written
                      6:  * by Eric Young (eay@cryptsoft.com).
                      7:  * The implementation was written so as to conform with Netscapes SSL.
                      8:  *
                      9:  * This library is free for commercial and non-commercial use as long as
                     10:  * the following conditions are aheared to.  The following conditions
                     11:  * apply to all code found in this distribution, be it the RC4, RSA,
                     12:  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
                     13:  * included with this distribution is covered by the same copyright terms
                     14:  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
                     15:  *
                     16:  * Copyright remains Eric Young's, and as such any Copyright notices in
                     17:  * the code are not to be removed.
                     18:  * If this package is used in a product, Eric Young should be given attribution
                     19:  * as the author of the parts of the library used.
                     20:  * This can be in the form of a textual message at program startup or
                     21:  * in documentation (online or textual) provided with the package.
                     22:  *
                     23:  * Redistribution and use in source and binary forms, with or without
                     24:  * modification, are permitted provided that the following conditions
                     25:  * are met:
                     26:  * 1. Redistributions of source code must retain the copyright
                     27:  *    notice, this list of conditions and the following disclaimer.
                     28:  * 2. Redistributions in binary form must reproduce the above copyright
                     29:  *    notice, this list of conditions and the following disclaimer in the
                     30:  *    documentation and/or other materials provided with the distribution.
                     31:  * 3. All advertising materials mentioning features or use of this software
                     32:  *    must display the following acknowledgement:
                     33:  *    "This product includes cryptographic software written by
                     34:  *     Eric Young (eay@cryptsoft.com)"
                     35:  *    The word 'cryptographic' can be left out if the rouines from the library
                     36:  *    being used are not cryptographic related :-).
                     37:  * 4. If you include any Windows specific code (or a derivative thereof) from
                     38:  *    the apps directory (application code) you must include an acknowledgement:
                     39:  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
                     40:  *
                     41:  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
                     42:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     43:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     44:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     45:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     46:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     47:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     48:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     49:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     50:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     51:  * SUCH DAMAGE.
                     52:  *
                     53:  * The licence and distribution terms for any publically available version or
                     54:  * derivative of this code cannot be changed.  i.e. this code cannot simply be
                     55:  * copied and put under another distribution licence
                     56:  * [including the GNU Public Licence.]
                     57:  */
                     58:
                     59: #include <assert.h>
1.20      inoguchi   60: #include <limits.h>
1.1       jsing      61: #include <stdio.h>
                     62: #include <stdlib.h>
                     63: #include <string.h>
                     64:
                     65: #include "apps.h"
                     66:
                     67: #include <openssl/asn1.h>
                     68: #include <openssl/bio.h>
                     69: #include <openssl/bn.h>
1.20      inoguchi   70: #include <openssl/dsa.h>
1.1       jsing      71: #include <openssl/err.h>
                     72: #include <openssl/evp.h>
                     73: #include <openssl/objects.h>
                     74: #include <openssl/pem.h>
1.20      inoguchi   75: #include <openssl/rsa.h>
1.1       jsing      76: #include <openssl/x509.h>
                     77: #include <openssl/x509v3.h>
                     78:
                     79: #define        POSTFIX ".srl"
                     80: #define DEF_DAYS       30
                     81:
                     82: static int callb(int ok, X509_STORE_CTX *ctx);
                     83: static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext,
                     84:     const EVP_MD *digest, CONF *conf, char *section);
                     85: static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
                     86:     X509 *x, X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts,
                     87:     char *serial, int create, int days, int clrext, CONF *conf, char *section,
                     88:     ASN1_INTEGER *sno);
                     89: static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt);
1.19      inoguchi   90:
                     91: static struct {
                     92:        char *alias;
                     93:        int aliasout;
                     94:        int badops;
                     95:        int C;
                     96:        int CA_createserial;
                     97:        int CA_flag;
                     98:        char *CAfile;
                     99:        int CAformat;
                    100:        char *CAkeyfile;
                    101:        int CAkeyformat;
                    102:        char *CAserial;
                    103:        unsigned long certflag;
                    104:        int checkend;
                    105:        int checkoffset;
                    106:        int clrext;
                    107:        int clrreject;
                    108:        int clrtrust;
                    109:        int days;
                    110:        const EVP_MD *digest;
                    111:        int email;
                    112:        int enddate;
                    113:        char *extfile;
                    114:        char *extsect;
                    115:        int fingerprint;
                    116:        char *infile;
                    117:        int informat;
                    118:        int issuer;
                    119:        int issuer_hash;
                    120: #ifndef OPENSSL_NO_MD5
                    121:        int issuer_hash_old;
                    122: #endif
                    123:        char *keyfile;
                    124:        int keyformat;
                    125:        const EVP_MD *md_alg;
                    126:        int modulus;
                    127:        int next_serial;
                    128:        unsigned long nmflag;
                    129:        int noout;
                    130:        int num;
                    131:        int ocspid;
                    132:        ASN1_OBJECT *objtmp;
                    133:        int ocsp_uri;
                    134:        char *outfile;
                    135:        int outformat;
                    136:        char *passargin;
                    137:        int pprint;
                    138:        int pubkey;
                    139:        STACK_OF(ASN1_OBJECT) *reject;
                    140:        int reqfile;
                    141:        int serial;
                    142:        int sign_flag;
                    143:        STACK_OF(OPENSSL_STRING) *sigopts;
                    144:        ASN1_INTEGER *sno;
                    145:        int startdate;
                    146:        int subject;
                    147:        int subject_hash;
                    148: #ifndef OPENSSL_NO_MD5
                    149:        int subject_hash_old;
                    150: #endif
                    151:        int text;
                    152:        STACK_OF(ASN1_OBJECT) *trust;
                    153:        int trustout;
                    154:        int x509req;
1.31      tb        155: } cfg;
1.19      inoguchi  156:
                    157: static int
                    158: x509_opt_addreject(char *arg)
                    159: {
1.31      tb        160:        if ((cfg.objtmp = OBJ_txt2obj(arg, 0)) == NULL) {
1.19      inoguchi  161:                BIO_printf(bio_err, "Invalid reject object value %s\n", arg);
                    162:                return (1);
                    163:        }
                    164:
1.31      tb        165:        if (cfg.reject == NULL &&
                    166:            (cfg.reject = sk_ASN1_OBJECT_new_null()) == NULL)
1.19      inoguchi  167:                return (1);
                    168:
1.31      tb        169:        if (!sk_ASN1_OBJECT_push(cfg.reject, cfg.objtmp))
1.19      inoguchi  170:                return (1);
                    171:
1.31      tb        172:        cfg.trustout = 1;
1.19      inoguchi  173:        return (0);
                    174: }
                    175:
                    176: static int
                    177: x509_opt_addtrust(char *arg)
                    178: {
1.31      tb        179:        if ((cfg.objtmp = OBJ_txt2obj(arg, 0)) == NULL) {
1.19      inoguchi  180:                BIO_printf(bio_err, "Invalid trust object value %s\n", arg);
                    181:                return (1);
                    182:        }
                    183:
1.31      tb        184:        if (cfg.trust == NULL &&
                    185:            (cfg.trust = sk_ASN1_OBJECT_new_null()) == NULL)
1.19      inoguchi  186:                return (1);
                    187:
1.31      tb        188:        if (!sk_ASN1_OBJECT_push(cfg.trust, cfg.objtmp))
1.19      inoguchi  189:                return (1);
                    190:
1.31      tb        191:        cfg.trustout = 1;
1.19      inoguchi  192:        return (0);
                    193: }
                    194:
                    195: static int
                    196: x509_opt_ca(char *arg)
                    197: {
1.31      tb        198:        cfg.CAfile = arg;
                    199:        cfg.CA_flag = ++cfg.num;
1.19      inoguchi  200:        return (0);
                    201: }
                    202:
                    203: static int
                    204: x509_opt_certopt(char *arg)
                    205: {
1.31      tb        206:        if (!set_cert_ex(&cfg.certflag, arg))
1.19      inoguchi  207:                return (1);
                    208:
                    209:        return (0);
                    210: }
                    211:
                    212: static int
                    213: x509_opt_checkend(char *arg)
                    214: {
                    215:        const char *errstr;
                    216:
1.31      tb        217:        cfg.checkoffset = strtonum(arg, 0, INT_MAX, &errstr);
1.19      inoguchi  218:        if (errstr != NULL) {
                    219:                BIO_printf(bio_err, "checkend unusable: %s\n", errstr);
                    220:                return (1);
                    221:        }
1.31      tb        222:        cfg.checkend = 1;
1.19      inoguchi  223:        return (0);
                    224: }
                    225:
                    226: static int
                    227: x509_opt_dates(void)
                    228: {
1.31      tb        229:        cfg.startdate = ++cfg.num;
                    230:        cfg.enddate = ++cfg.num;
1.19      inoguchi  231:        return (0);
                    232: }
                    233:
                    234: static int
                    235: x509_opt_days(char *arg)
                    236: {
                    237:        const char *errstr;
                    238:
1.31      tb        239:        cfg.days = strtonum(arg, 1, INT_MAX, &errstr);
1.19      inoguchi  240:        if (errstr != NULL) {
                    241:                BIO_printf(bio_err, "bad number of days: %s\n", errstr);
                    242:                return (1);
                    243:        }
                    244:        return (0);
                    245: }
                    246:
                    247: static int
                    248: x509_opt_digest(int argc, char **argv, int *argsused)
                    249: {
                    250:        char *name = argv[0];
                    251:
                    252:        if (*name++ != '-')
                    253:                return (1);
                    254:
1.31      tb        255:        if ((cfg.md_alg = EVP_get_digestbyname(name)) != NULL) {
                    256:                cfg.digest = cfg.md_alg;
1.19      inoguchi  257:        } else {
                    258:                BIO_printf(bio_err, "unknown option %s\n", *argv);
1.31      tb        259:                cfg.badops = 1;
1.19      inoguchi  260:                return (1);
                    261:        }
                    262:
                    263:        *argsused = 1;
                    264:        return (0);
                    265: }
                    266:
                    267: static int
                    268: x509_opt_nameopt(char *arg)
                    269: {
1.31      tb        270:        if (!set_name_ex(&cfg.nmflag, arg))
1.19      inoguchi  271:                return (1);
                    272:
                    273:        return (0);
                    274: }
                    275:
                    276: static int
                    277: x509_opt_set_serial(char *arg)
                    278: {
1.31      tb        279:        ASN1_INTEGER_free(cfg.sno);
                    280:        if ((cfg.sno = s2i_ASN1_INTEGER(NULL, arg)) == NULL)
1.19      inoguchi  281:                return (1);
                    282:
                    283:        return (0);
                    284: }
                    285:
                    286: static int
                    287: x509_opt_setalias(char *arg)
                    288: {
1.31      tb        289:        cfg.alias = arg;
                    290:        cfg.trustout = 1;
1.19      inoguchi  291:        return (0);
                    292: }
                    293:
                    294: static int
                    295: x509_opt_signkey(char *arg)
                    296: {
1.31      tb        297:        cfg.keyfile = arg;
                    298:        cfg.sign_flag = ++cfg.num;
1.19      inoguchi  299:        return (0);
                    300: }
                    301:
                    302: static int
                    303: x509_opt_sigopt(char *arg)
                    304: {
1.31      tb        305:        if (cfg.sigopts == NULL &&
                    306:            (cfg.sigopts = sk_OPENSSL_STRING_new_null()) == NULL)
1.19      inoguchi  307:                return (1);
                    308:
1.31      tb        309:        if (!sk_OPENSSL_STRING_push(cfg.sigopts, arg))
1.19      inoguchi  310:                return (1);
                    311:
                    312:        return (0);
                    313: }
                    314:
                    315: static const struct option x509_options[] = {
                    316:        {
                    317:                .name = "C",
                    318:                .desc = "Convert the certificate into C code",
                    319:                .type = OPTION_ORDER,
1.31      tb        320:                .opt.order = &cfg.C,
                    321:                .order = &cfg.num,
1.19      inoguchi  322:        },
                    323:        {
                    324:                .name = "addreject",
                    325:                .argname = "arg",
                    326:                .desc = "Reject certificate for a given purpose",
                    327:                .type = OPTION_ARG_FUNC,
                    328:                .opt.argfunc = x509_opt_addreject,
                    329:        },
                    330:        {
                    331:                .name = "addtrust",
                    332:                .argname = "arg",
                    333:                .desc = "Trust certificate for a given purpose",
                    334:                .type = OPTION_ARG_FUNC,
                    335:                .opt.argfunc = x509_opt_addtrust,
                    336:        },
                    337:        {
                    338:                .name = "alias",
                    339:                .desc = "Output certificate alias",
                    340:                .type = OPTION_ORDER,
1.31      tb        341:                .opt.order = &cfg.aliasout,
                    342:                .order = &cfg.num,
1.19      inoguchi  343:        },
                    344:        {
                    345:                .name = "CA",
                    346:                .argname = "file",
                    347:                .desc = "CA certificate in PEM format unless -CAform is specified",
                    348:                .type = OPTION_ARG_FUNC,
                    349:                .opt.argfunc = x509_opt_ca,
                    350:        },
                    351:        {
                    352:                .name = "CAcreateserial",
                    353:                .desc = "Create serial number file if it does not exist",
                    354:                .type = OPTION_ORDER,
1.31      tb        355:                .opt.order = &cfg.CA_createserial,
                    356:                .order = &cfg.num,
1.19      inoguchi  357:        },
                    358:        {
                    359:                .name = "CAform",
                    360:                .argname = "fmt",
                    361:                .desc = "CA format - default PEM",
                    362:                .type = OPTION_ARG_FORMAT,
1.31      tb        363:                .opt.value = &cfg.CAformat,
1.19      inoguchi  364:        },
                    365:        {
                    366:                .name = "CAkey",
                    367:                .argname = "file",
                    368:                .desc = "CA key in PEM format unless -CAkeyform is specified\n"
                    369:                        "if omitted, the key is assumed to be in the CA file",
                    370:                .type = OPTION_ARG,
1.31      tb        371:                .opt.arg = &cfg.CAkeyfile,
1.19      inoguchi  372:        },
                    373:        {
                    374:                .name = "CAkeyform",
                    375:                .argname = "fmt",
                    376:                .desc = "CA key format - default PEM",
                    377:                .type = OPTION_ARG_FORMAT,
1.31      tb        378:                .opt.value = &cfg.CAkeyformat,
1.19      inoguchi  379:        },
                    380:        {
                    381:                .name = "CAserial",
                    382:                .argname = "file",
                    383:                .desc = "Serial file",
                    384:                .type = OPTION_ARG,
1.31      tb        385:                .opt.arg = &cfg.CAserial,
1.19      inoguchi  386:        },
                    387:        {
                    388:                .name = "certopt",
                    389:                .argname = "option",
                    390:                .desc = "Various certificate text options",
                    391:                .type = OPTION_ARG_FUNC,
                    392:                .opt.argfunc = x509_opt_certopt,
                    393:        },
                    394:        {
                    395:                .name = "checkend",
                    396:                .argname = "arg",
                    397:                .desc = "Check whether the cert expires in the next arg seconds\n"
                    398:                        "exit 1 if so, 0 if not",
                    399:                .type = OPTION_ARG_FUNC,
                    400:                .opt.argfunc = x509_opt_checkend,
                    401:        },
                    402:        {
                    403:                .name = "clrext",
                    404:                .desc = "Clear all extensions",
                    405:                .type = OPTION_FLAG,
1.31      tb        406:                .opt.flag = &cfg.clrext,
1.19      inoguchi  407:        },
                    408:        {
                    409:                .name = "clrreject",
                    410:                .desc = "Clear all rejected purposes",
                    411:                .type = OPTION_ORDER,
1.31      tb        412:                .opt.order = &cfg.clrreject,
                    413:                .order = &cfg.num,
1.19      inoguchi  414:        },
                    415:        {
                    416:                .name = "clrtrust",
                    417:                .desc = "Clear all trusted purposes",
                    418:                .type = OPTION_ORDER,
1.31      tb        419:                .opt.order = &cfg.clrtrust,
                    420:                .order = &cfg.num,
1.19      inoguchi  421:        },
                    422:        {
                    423:                .name = "dates",
                    424:                .desc = "Both Before and After dates",
                    425:                .type = OPTION_FUNC,
                    426:                .opt.func = x509_opt_dates,
                    427:        },
                    428:        {
                    429:                .name = "days",
                    430:                .argname = "arg",
                    431:                .desc = "How long till expiry of a signed certificate - def 30 days",
                    432:                .type = OPTION_ARG_FUNC,
                    433:                .opt.argfunc = x509_opt_days,
                    434:        },
                    435:        {
                    436:                .name = "email",
                    437:                .desc = "Print email address(es)",
                    438:                .type = OPTION_ORDER,
1.31      tb        439:                .opt.order = &cfg.email,
                    440:                .order = &cfg.num,
1.19      inoguchi  441:        },
                    442:        {
                    443:                .name = "enddate",
                    444:                .desc = "Print notAfter field",
                    445:                .type = OPTION_ORDER,
1.31      tb        446:                .opt.order = &cfg.enddate,
                    447:                .order = &cfg.num,
1.19      inoguchi  448:        },
                    449:        {
                    450:                .name = "extensions",
                    451:                .argname = "section",
                    452:                .desc = "Section from config file with X509V3 extensions to add",
                    453:                .type = OPTION_ARG,
1.31      tb        454:                .opt.arg = &cfg.extsect,
1.19      inoguchi  455:        },
                    456:        {
                    457:                .name = "extfile",
                    458:                .argname = "file",
                    459:                .desc = "Configuration file with X509V3 extensions to add",
                    460:                .type = OPTION_ARG,
1.31      tb        461:                .opt.arg = &cfg.extfile,
1.19      inoguchi  462:        },
                    463:        {
                    464:                .name = "fingerprint",
                    465:                .desc = "Print the certificate fingerprint",
                    466:                .type = OPTION_ORDER,
1.31      tb        467:                .opt.order = &cfg.fingerprint,
                    468:                .order = &cfg.num,
1.19      inoguchi  469:        },
                    470:        {
                    471:                .name = "hash",
                    472:                .desc = "Synonym for -subject_hash",
                    473:                .type = OPTION_ORDER,
1.31      tb        474:                .opt.order = &cfg.subject_hash,
                    475:                .order = &cfg.num,
1.19      inoguchi  476:        },
                    477:        {
                    478:                .name = "in",
                    479:                .argname = "file",
                    480:                .desc = "Input file - default stdin",
                    481:                .type = OPTION_ARG,
1.31      tb        482:                .opt.arg = &cfg.infile,
1.19      inoguchi  483:        },
                    484:        {
                    485:                .name = "inform",
                    486:                .argname = "fmt",
                    487:                .desc = "Input format - default PEM (one of DER, NET or PEM)",
                    488:                .type = OPTION_ARG_FORMAT,
1.31      tb        489:                .opt.value = &cfg.informat,
1.19      inoguchi  490:        },
                    491:        {
                    492:                .name = "issuer",
                    493:                .desc = "Print issuer name",
                    494:                .type = OPTION_ORDER,
1.31      tb        495:                .opt.order = &cfg.issuer,
                    496:                .order = &cfg.num,
1.19      inoguchi  497:        },
                    498:        {
                    499:                .name = "issuer_hash",
                    500:                .desc = "Print issuer hash value",
                    501:                .type = OPTION_ORDER,
1.31      tb        502:                .opt.order = &cfg.issuer_hash,
                    503:                .order = &cfg.num,
1.19      inoguchi  504:        },
                    505: #ifndef OPENSSL_NO_MD5
                    506:        {
                    507:                .name = "issuer_hash_old",
                    508:                .desc = "Print old-style (MD5) issuer hash value",
                    509:                .type = OPTION_ORDER,
1.31      tb        510:                .opt.order = &cfg.issuer_hash_old,
                    511:                .order = &cfg.num,
1.19      inoguchi  512:        },
                    513: #endif
                    514:        {
                    515:                .name = "keyform",
                    516:                .argname = "fmt",
                    517:                .desc = "Private key format - default PEM",
                    518:                .type = OPTION_ARG_FORMAT,
1.31      tb        519:                .opt.value = &cfg.keyformat,
1.19      inoguchi  520:        },
                    521:        {
                    522:                .name = "modulus",
                    523:                .desc = "Print the RSA key modulus",
                    524:                .type = OPTION_ORDER,
1.31      tb        525:                .opt.order = &cfg.modulus,
                    526:                .order = &cfg.num,
1.19      inoguchi  527:        },
                    528:        {
                    529:                .name = "nameopt",
                    530:                .argname = "option",
                    531:                .desc = "Various certificate name options",
                    532:                .type = OPTION_ARG_FUNC,
                    533:                .opt.argfunc = x509_opt_nameopt,
                    534:        },
                    535:        {
                    536:                .name = "next_serial",
                    537:                .desc = "Print the next serial number",
                    538:                .type = OPTION_ORDER,
1.31      tb        539:                .opt.order = &cfg.next_serial,
                    540:                .order = &cfg.num,
1.19      inoguchi  541:        },
                    542:        {
                    543:                .name = "noout",
                    544:                .desc = "No certificate output",
                    545:                .type = OPTION_ORDER,
1.31      tb        546:                .opt.order = &cfg.noout,
                    547:                .order = &cfg.num,
1.19      inoguchi  548:        },
                    549:        {
                    550:                .name = "ocsp_uri",
                    551:                .desc = "Print OCSP Responder URL(s)",
                    552:                .type = OPTION_ORDER,
1.31      tb        553:                .opt.order = &cfg.ocsp_uri,
                    554:                .order = &cfg.num,
1.19      inoguchi  555:        },
                    556:        {
                    557:                .name = "ocspid",
                    558:                .desc = "Print OCSP hash values for the subject name and public key",
                    559:                .type = OPTION_ORDER,
1.31      tb        560:                .opt.order = &cfg.ocspid,
                    561:                .order = &cfg.num,
1.19      inoguchi  562:        },
                    563:        {
                    564:                .name = "out",
                    565:                .argname = "file",
                    566:                .desc = "Output file - default stdout",
                    567:                .type = OPTION_ARG,
1.31      tb        568:                .opt.arg = &cfg.outfile,
1.19      inoguchi  569:        },
                    570:        {
                    571:                .name = "outform",
                    572:                .argname = "fmt",
                    573:                .desc = "Output format - default PEM (one of DER, NET or PEM)",
                    574:                .type = OPTION_ARG_FORMAT,
1.31      tb        575:                .opt.value = &cfg.outformat,
1.19      inoguchi  576:        },
                    577:        {
                    578:                .name = "passin",
                    579:                .argname = "src",
                    580:                .desc = "Private key password source",
                    581:                .type = OPTION_ARG,
1.31      tb        582:                .opt.arg = &cfg.passargin,
1.19      inoguchi  583:        },
                    584:        {
                    585:                .name = "pubkey",
                    586:                .desc = "Output the public key",
                    587:                .type = OPTION_ORDER,
1.31      tb        588:                .opt.order = &cfg.pubkey,
                    589:                .order = &cfg.num,
1.19      inoguchi  590:        },
                    591:        {
                    592:                .name = "purpose",
                    593:                .desc = "Print out certificate purposes",
                    594:                .type = OPTION_ORDER,
1.31      tb        595:                .opt.order = &cfg.pprint,
                    596:                .order = &cfg.num,
1.19      inoguchi  597:        },
                    598:        {
                    599:                .name = "req",
                    600:                .desc = "Input is a certificate request, sign and output",
                    601:                .type = OPTION_FLAG,
1.31      tb        602:                .opt.flag = &cfg.reqfile,
1.19      inoguchi  603:        },
                    604:        {
                    605:                .name = "serial",
                    606:                .desc = "Print serial number value",
                    607:                .type = OPTION_ORDER,
1.31      tb        608:                .opt.order = &cfg.serial,
                    609:                .order = &cfg.num,
1.19      inoguchi  610:        },
                    611:        {
                    612:                .name = "set_serial",
                    613:                .argname = "n",
                    614:                .desc = "Serial number to use",
                    615:                .type = OPTION_ARG_FUNC,
                    616:                .opt.argfunc = x509_opt_set_serial,
                    617:        },
                    618:        {
                    619:                .name = "setalias",
                    620:                .argname = "arg",
                    621:                .desc = "Set certificate alias",
                    622:                .type = OPTION_ARG_FUNC,
                    623:                .opt.argfunc = x509_opt_setalias,
                    624:        },
                    625:        {
                    626:                .name = "signkey",
                    627:                .argname = "file",
                    628:                .desc = "Self sign cert with arg",
                    629:                .type = OPTION_ARG_FUNC,
                    630:                .opt.argfunc = x509_opt_signkey,
                    631:        },
                    632:        {
                    633:                .name = "sigopt",
                    634:                .argname = "nm:v",
                    635:                .desc = "Various signature algorithm options",
                    636:                .type = OPTION_ARG_FUNC,
                    637:                .opt.argfunc = x509_opt_sigopt,
                    638:        },
                    639:        {
                    640:                .name = "startdate",
                    641:                .desc = "Print notBefore field",
                    642:                .type = OPTION_ORDER,
1.31      tb        643:                .opt.order = &cfg.startdate,
                    644:                .order = &cfg.num,
1.19      inoguchi  645:        },
                    646:        {
                    647:                .name = "subject",
                    648:                .desc = "Print subject name",
                    649:                .type = OPTION_ORDER,
1.31      tb        650:                .opt.order = &cfg.subject,
                    651:                .order = &cfg.num,
1.19      inoguchi  652:        },
                    653:        {
                    654:                .name = "subject_hash",
                    655:                .desc = "Print subject hash value",
                    656:                .type = OPTION_ORDER,
1.31      tb        657:                .opt.order = &cfg.subject_hash,
                    658:                .order = &cfg.num,
1.19      inoguchi  659:        },
                    660: #ifndef OPENSSL_NO_MD5
                    661:        {
                    662:                .name = "subject_hash_old",
                    663:                .desc = "Print old-style (MD5) subject hash value",
                    664:                .type = OPTION_ORDER,
1.31      tb        665:                .opt.order = &cfg.subject_hash_old,
                    666:                .order = &cfg.num,
1.19      inoguchi  667:        },
                    668: #endif
                    669:        {
                    670:                .name = "text",
                    671:                .desc = "Print the certificate in text form",
                    672:                .type = OPTION_ORDER,
1.31      tb        673:                .opt.order = &cfg.text,
                    674:                .order = &cfg.num,
1.19      inoguchi  675:        },
                    676:        {
                    677:                .name = "trustout",
                    678:                .desc = "Output a trusted certificate",
                    679:                .type = OPTION_FLAG,
1.31      tb        680:                .opt.flag = &cfg.trustout,
1.19      inoguchi  681:        },
                    682:        {
                    683:                .name = "x509toreq",
                    684:                .desc = "Output a certification request object",
                    685:                .type = OPTION_ORDER,
1.31      tb        686:                .opt.order = &cfg.x509req,
                    687:                .order = &cfg.num,
1.19      inoguchi  688:        },
                    689:        {
                    690:                .name = NULL,
                    691:                .desc = "",
                    692:                .type = OPTION_ARGV_FUNC,
                    693:                .opt.argvfunc = x509_opt_digest,
                    694:        },
                    695:        { NULL },
                    696: };
                    697:
                    698: static void
                    699: x509_usage(void)
                    700: {
                    701:        fprintf(stderr, "usage: x509 "
                    702:            "[-C] [-addreject arg] [-addtrust arg] [-alias] [-CA file]\n"
                    703:            "    [-CAcreateserial] [-CAform der | pem] [-CAkey file]\n"
                    704:            "    [-CAkeyform der | pem] [-CAserial file] [-certopt option]\n"
                    705:            "    [-checkend arg] [-clrext] [-clrreject] [-clrtrust] [-dates]\n"
                    706:            "    [-days arg] [-email] [-enddate] [-extensions section]\n"
                    707:            "    [-extfile file] [-fingerprint] [-hash] [-in file]\n"
                    708:            "    [-inform der | net | pem] [-issuer] [-issuer_hash]\n"
                    709:            "    [-issuer_hash_old] [-keyform der | pem] [-md5 | -sha1]\n"
                    710:            "    [-modulus] [-nameopt option] [-next_serial] [-noout]\n"
                    711:            "    [-ocsp_uri] [-ocspid] [-out file]\n"
                    712:            "    [-outform der | net | pem] [-passin arg] [-pubkey]\n"
                    713:            "    [-purpose] [-req] [-serial] [-set_serial n] [-setalias arg]\n"
                    714:            "    [-signkey file] [-sigopt nm:v] [-startdate] [-subject]\n"
                    715:            "    [-subject_hash] [-subject_hash_old] [-text] [-trustout]\n"
                    716:            "    [-x509toreq]\n");
                    717:        fprintf(stderr, "\n");
                    718:        options_usage(x509_options);
                    719:        fprintf(stderr, "\n");
                    720: }
1.1       jsing     721:
                    722: int
                    723: x509_main(int argc, char **argv)
                    724: {
                    725:        int ret = 1;
                    726:        X509_REQ *req = NULL;
                    727:        X509 *x = NULL, *xca = NULL;
                    728:        EVP_PKEY *Upkey = NULL, *CApkey = NULL;
1.19      inoguchi  729:        int i;
1.1       jsing     730:        BIO *out = NULL;
                    731:        BIO *STDout = NULL;
                    732:        X509_STORE *ctx = NULL;
                    733:        X509_REQ *rq = NULL;
                    734:        char buf[256];
                    735:        CONF *extconf = NULL;
1.19      inoguchi  736:        char *passin = NULL;
1.10      doug      737:
1.30      joshua    738:        if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
                    739:                perror("pledge");
                    740:                exit(1);
1.10      doug      741:        }
1.1       jsing     742:
1.31      tb        743:        memset(&cfg, 0, sizeof(cfg));
                    744:        cfg.days = DEF_DAYS;
                    745:        cfg.informat = FORMAT_PEM;
                    746:        cfg.outformat = FORMAT_PEM;
                    747:        cfg.keyformat = FORMAT_PEM;
                    748:        cfg.CAformat = FORMAT_PEM;
                    749:        cfg.CAkeyformat = FORMAT_PEM;
1.1       jsing     750:
                    751:        STDout = BIO_new_fp(stdout, BIO_NOCLOSE);
                    752:
                    753:        ctx = X509_STORE_new();
                    754:        if (ctx == NULL)
                    755:                goto end;
                    756:        X509_STORE_set_verify_cb(ctx, callb);
                    757:
1.19      inoguchi  758:        if (options_parse(argc, argv, x509_options, NULL, NULL) != 0)
                    759:                goto bad;
1.1       jsing     760:
1.31      tb        761:        if (cfg.badops) {
1.16      jsing     762:  bad:
1.19      inoguchi  763:                x509_usage();
1.1       jsing     764:                goto end;
                    765:        }
                    766:
1.31      tb        767:        if (!app_passwd(bio_err, cfg.passargin, NULL, &passin, NULL)) {
1.1       jsing     768:                BIO_printf(bio_err, "Error getting password\n");
                    769:                goto end;
                    770:        }
                    771:        if (!X509_STORE_set_default_paths(ctx)) {
                    772:                ERR_print_errors(bio_err);
                    773:                goto end;
                    774:        }
1.32    ! tb        775:        if (cfg.CAkeyfile == NULL && cfg.CA_flag && cfg.CAformat == FORMAT_PEM) {
1.31      tb        776:                cfg.CAkeyfile = cfg.CAfile;
1.32    ! tb        777:        } else if (cfg.CA_flag && cfg.CAkeyfile == NULL) {
1.1       jsing     778:                BIO_printf(bio_err,
                    779:                    "need to specify a CAkey if using the CA command\n");
                    780:                goto end;
                    781:        }
1.31      tb        782:        if (cfg.extfile != NULL) {
1.1       jsing     783:                long errorline = -1;
                    784:                X509V3_CTX ctx2;
                    785:                extconf = NCONF_new(NULL);
1.31      tb        786:                if (!NCONF_load(extconf, cfg.extfile, &errorline)) {
1.1       jsing     787:                        if (errorline <= 0)
                    788:                                BIO_printf(bio_err,
                    789:                                    "error loading the config file '%s'\n",
1.31      tb        790:                                    cfg.extfile);
1.1       jsing     791:                        else
                    792:                                BIO_printf(bio_err,
                    793:                                    "error on line %ld of config file '%s'\n",
1.31      tb        794:                                    errorline, cfg.extfile);
1.1       jsing     795:                        goto end;
                    796:                }
1.31      tb        797:                if (cfg.extsect == NULL) {
1.32    ! tb        798:                        cfg.extsect = NCONF_get_string(extconf, "default",
        !           799:                            "extensions");
1.31      tb        800:                        if (cfg.extsect == NULL) {
1.1       jsing     801:                                ERR_clear_error();
1.31      tb        802:                                cfg.extsect = "default";
1.1       jsing     803:                        }
                    804:                }
                    805:                X509V3_set_ctx_test(&ctx2);
                    806:                X509V3_set_nconf(&ctx2, extconf);
1.32    ! tb        807:                if (!X509V3_EXT_add_nconf(extconf, &ctx2, cfg.extsect, NULL)) {
1.1       jsing     808:                        BIO_printf(bio_err,
1.32    ! tb        809:                            "Error Loading extension section %s\n", cfg.extsect);
1.1       jsing     810:                        ERR_print_errors(bio_err);
                    811:                        goto end;
                    812:                }
                    813:        }
1.31      tb        814:        if (cfg.reqfile) {
1.1       jsing     815:                EVP_PKEY *pkey;
                    816:                BIO *in;
                    817:
1.31      tb        818:                if (!cfg.sign_flag && !cfg.CA_flag) {
1.20      inoguchi  819:                        BIO_printf(bio_err,
                    820:                            "We need a private key to sign with\n");
1.1       jsing     821:                        goto end;
                    822:                }
                    823:                in = BIO_new(BIO_s_file());
                    824:                if (in == NULL) {
                    825:                        ERR_print_errors(bio_err);
                    826:                        goto end;
                    827:                }
1.31      tb        828:                if (cfg.infile == NULL)
1.1       jsing     829:                        BIO_set_fp(in, stdin, BIO_NOCLOSE | BIO_FP_TEXT);
                    830:                else {
1.31      tb        831:                        if (BIO_read_filename(in, cfg.infile) <= 0) {
                    832:                                perror(cfg.infile);
1.1       jsing     833:                                BIO_free(in);
                    834:                                goto end;
                    835:                        }
                    836:                }
                    837:                req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
                    838:                BIO_free(in);
                    839:
                    840:                if (req == NULL) {
                    841:                        ERR_print_errors(bio_err);
                    842:                        goto end;
                    843:                }
1.29      tb        844:                if ((pkey = X509_REQ_get0_pubkey(req)) == NULL) {
1.1       jsing     845:                        BIO_printf(bio_err, "error unpacking public key\n");
                    846:                        goto end;
                    847:                }
                    848:                i = X509_REQ_verify(req, pkey);
                    849:                if (i < 0) {
                    850:                        BIO_printf(bio_err, "Signature verification error\n");
                    851:                        ERR_print_errors(bio_err);
                    852:                        goto end;
                    853:                }
                    854:                if (i == 0) {
1.20      inoguchi  855:                        BIO_printf(bio_err,
                    856:                            "Signature did not match the certificate request\n");
1.1       jsing     857:                        goto end;
                    858:                } else
                    859:                        BIO_printf(bio_err, "Signature ok\n");
                    860:
1.20      inoguchi  861:                print_name(bio_err, "subject=", X509_REQ_get_subject_name(req),
1.31      tb        862:                    cfg.nmflag);
1.1       jsing     863:
                    864:                if ((x = X509_new()) == NULL)
                    865:                        goto end;
                    866:
1.31      tb        867:                if (cfg.sno == NULL) {
                    868:                        cfg.sno = ASN1_INTEGER_new();
1.32    ! tb        869:                        if (cfg.sno == NULL || !rand_serial(NULL, cfg.sno))
1.1       jsing     870:                                goto end;
1.31      tb        871:                        if (!X509_set_serialNumber(x, cfg.sno))
1.1       jsing     872:                                goto end;
1.31      tb        873:                        ASN1_INTEGER_free(cfg.sno);
                    874:                        cfg.sno = NULL;
                    875:                } else if (!X509_set_serialNumber(x, cfg.sno))
1.1       jsing     876:                        goto end;
                    877:
1.25      tb        878:                if (!X509_set_issuer_name(x, X509_REQ_get_subject_name(req)))
1.1       jsing     879:                        goto end;
1.25      tb        880:                if (!X509_set_subject_name(x, X509_REQ_get_subject_name(req)))
1.1       jsing     881:                        goto end;
                    882:
1.23      inoguchi  883:                if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL)
                    884:                        goto end;
1.31      tb        885:                if (X509_time_adj_ex(X509_get_notAfter(x), cfg.days, 0,
1.23      inoguchi  886:                    NULL) == NULL)
                    887:                        goto end;
1.1       jsing     888:
1.29      tb        889:                if ((pkey = X509_REQ_get0_pubkey(req)) == NULL)
1.23      inoguchi  890:                        goto end;
                    891:                if (!X509_set_pubkey(x, pkey)) {
                    892:                        EVP_PKEY_free(pkey);
                    893:                        goto end;
                    894:                }
                    895:        } else {
1.32    ! tb        896:                x = load_cert(bio_err, cfg.infile, cfg.informat, NULL,
        !           897:                    "Certificate");
1.23      inoguchi  898:        }
1.1       jsing     899:        if (x == NULL)
                    900:                goto end;
1.23      inoguchi  901:
1.31      tb        902:        if (cfg.CA_flag) {
1.32    ! tb        903:                xca = load_cert(bio_err, cfg.CAfile, cfg.CAformat, NULL,
        !           904:                    "CA Certificate");
1.1       jsing     905:                if (xca == NULL)
                    906:                        goto end;
                    907:        }
1.31      tb        908:        if (!cfg.noout || cfg.text || cfg.next_serial) {
1.20      inoguchi  909:                OBJ_create("2.99999.3", "SET.ex3", "SET x509v3 extension 3");
1.1       jsing     910:
                    911:                out = BIO_new(BIO_s_file());
                    912:                if (out == NULL) {
                    913:                        ERR_print_errors(bio_err);
                    914:                        goto end;
                    915:                }
1.31      tb        916:                if (cfg.outfile == NULL) {
1.1       jsing     917:                        BIO_set_fp(out, stdout, BIO_NOCLOSE);
                    918:                } else {
1.31      tb        919:                        if (BIO_write_filename(out, cfg.outfile) <= 0) {
                    920:                                perror(cfg.outfile);
1.1       jsing     921:                                goto end;
                    922:                        }
                    923:                }
                    924:        }
1.31      tb        925:        if (cfg.alias != NULL) {
                    926:                if (!X509_alias_set1(x, (unsigned char *)cfg.alias, -1))
1.23      inoguchi  927:                        goto end;
                    928:        }
1.1       jsing     929:
1.31      tb        930:        if (cfg.clrtrust)
1.1       jsing     931:                X509_trust_clear(x);
1.31      tb        932:        if (cfg.clrreject)
1.1       jsing     933:                X509_reject_clear(x);
                    934:
1.31      tb        935:        if (cfg.trust != NULL) {
                    936:                for (i = 0; i < sk_ASN1_OBJECT_num(cfg.trust); i++) {
1.32    ! tb        937:                        cfg.objtmp = sk_ASN1_OBJECT_value(cfg.trust, i);
1.31      tb        938:                        if (!X509_add1_trust_object(x, cfg.objtmp))
1.23      inoguchi  939:                                goto end;
1.1       jsing     940:                }
                    941:        }
1.31      tb        942:        if (cfg.reject != NULL) {
                    943:                for (i = 0; i < sk_ASN1_OBJECT_num(cfg.reject); i++) {
1.32    ! tb        944:                        cfg.objtmp = sk_ASN1_OBJECT_value(cfg.reject, i);
1.31      tb        945:                        if (!X509_add1_reject_object(x, cfg.objtmp))
1.23      inoguchi  946:                                goto end;
1.1       jsing     947:                }
                    948:        }
1.31      tb        949:        if (cfg.num) {
                    950:                for (i = 1; i <= cfg.num; i++) {
                    951:                        if (cfg.issuer == i) {
1.1       jsing     952:                                print_name(STDout, "issuer= ",
1.32    ! tb        953:                                    X509_get_issuer_name(x), cfg.nmflag);
1.31      tb        954:                        } else if (cfg.subject == i) {
1.1       jsing     955:                                print_name(STDout, "subject= ",
1.32    ! tb        956:                                    X509_get_subject_name(x), cfg.nmflag);
1.31      tb        957:                        } else if (cfg.serial == i) {
1.1       jsing     958:                                BIO_printf(STDout, "serial=");
                    959:                                i2a_ASN1_INTEGER(STDout,
                    960:                                    X509_get_serialNumber(x));
                    961:                                BIO_printf(STDout, "\n");
1.31      tb        962:                        } else if (cfg.next_serial == i) {
1.1       jsing     963:                                BIGNUM *bnser;
                    964:                                ASN1_INTEGER *ser;
1.32    ! tb        965:
1.1       jsing     966:                                ser = X509_get_serialNumber(x);
1.23      inoguchi  967:                                if (ser == NULL)
                    968:                                        goto end;
1.1       jsing     969:                                bnser = ASN1_INTEGER_to_BN(ser, NULL);
1.21      inoguchi  970:                                if (bnser == NULL)
1.1       jsing     971:                                        goto end;
1.22      inoguchi  972:                                if (!BN_add_word(bnser, 1)) {
                    973:                                        BN_free(bnser);
1.1       jsing     974:                                        goto end;
1.22      inoguchi  975:                                }
1.1       jsing     976:                                ser = BN_to_ASN1_INTEGER(bnser, NULL);
1.22      inoguchi  977:                                if (ser == NULL) {
                    978:                                        BN_free(bnser);
1.1       jsing     979:                                        goto end;
1.22      inoguchi  980:                                }
1.1       jsing     981:                                BN_free(bnser);
                    982:                                i2a_ASN1_INTEGER(out, ser);
                    983:                                ASN1_INTEGER_free(ser);
                    984:                                BIO_puts(out, "\n");
1.32    ! tb        985:                        } else if (cfg.email == i || cfg.ocsp_uri == i) {
        !           986:                                STACK_OF(OPENSSL_STRING) *emlst;
1.1       jsing     987:                                int j;
1.32    ! tb        988:
1.31      tb        989:                                if (cfg.email == i)
1.1       jsing     990:                                        emlst = X509_get1_email(x);
                    991:                                else
                    992:                                        emlst = X509_get1_ocsp(x);
                    993:                                for (j = 0; j < sk_OPENSSL_STRING_num(emlst); j++)
                    994:                                        BIO_printf(STDout, "%s\n",
                    995:                                            sk_OPENSSL_STRING_value(emlst, j));
                    996:                                X509_email_free(emlst);
1.31      tb        997:                        } else if (cfg.aliasout == i) {
1.24      schwarze  998:                                unsigned char *albuf;
                    999:                                int buflen;
                   1000:                                albuf = X509_alias_get0(x, &buflen);
                   1001:                                if (albuf != NULL)
                   1002:                                        BIO_printf(STDout, "%.*s\n",
                   1003:                                            buflen, albuf);
1.1       jsing    1004:                                else
                   1005:                                        BIO_puts(STDout, "<No Alias>\n");
1.31      tb       1006:                        } else if (cfg.subject_hash == i) {
1.20      inoguchi 1007:                                BIO_printf(STDout, "%08lx\n",
                   1008:                                    X509_subject_name_hash(x));
1.1       jsing    1009:                        }
                   1010: #ifndef OPENSSL_NO_MD5
1.31      tb       1011:                        else if (cfg.subject_hash_old == i) {
1.20      inoguchi 1012:                                BIO_printf(STDout, "%08lx\n",
                   1013:                                    X509_subject_name_hash_old(x));
1.1       jsing    1014:                        }
                   1015: #endif
1.31      tb       1016:                        else if (cfg.issuer_hash == i) {
1.20      inoguchi 1017:                                BIO_printf(STDout, "%08lx\n",
                   1018:                                    X509_issuer_name_hash(x));
1.1       jsing    1019:                        }
                   1020: #ifndef OPENSSL_NO_MD5
1.31      tb       1021:                        else if (cfg.issuer_hash_old == i) {
1.20      inoguchi 1022:                                BIO_printf(STDout, "%08lx\n",
                   1023:                                    X509_issuer_name_hash_old(x));
1.1       jsing    1024:                        }
                   1025: #endif
1.31      tb       1026:                        else if (cfg.pprint == i) {
1.1       jsing    1027:                                X509_PURPOSE *ptmp;
                   1028:                                int j;
1.32    ! tb       1029:
1.1       jsing    1030:                                BIO_printf(STDout, "Certificate purposes:\n");
                   1031:                                for (j = 0; j < X509_PURPOSE_get_count(); j++) {
                   1032:                                        ptmp = X509_PURPOSE_get0(j);
                   1033:                                        purpose_print(STDout, x, ptmp);
                   1034:                                }
1.31      tb       1035:                        } else if (cfg.modulus == i) {
1.1       jsing    1036:                                EVP_PKEY *pkey;
                   1037:
1.28      tb       1038:                                pkey = X509_get0_pubkey(x);
1.1       jsing    1039:                                if (pkey == NULL) {
1.20      inoguchi 1040:                                        BIO_printf(bio_err,
                   1041:                                            "Modulus=unavailable\n");
1.1       jsing    1042:                                        ERR_print_errors(bio_err);
                   1043:                                        goto end;
                   1044:                                }
                   1045:                                BIO_printf(STDout, "Modulus=");
1.27      tb       1046:                                if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) {
                   1047:                                        RSA *rsa = EVP_PKEY_get0_RSA(pkey);
                   1048:                                        const BIGNUM *n = NULL;
                   1049:
                   1050:                                        RSA_get0_key(rsa, &n, NULL, NULL);
                   1051:                                        BN_print(STDout, n);
                   1052:                                } else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA) {
                   1053:                                        DSA *dsa = EVP_PKEY_get0_DSA(pkey);
                   1054:                                        const BIGNUM *pub_key = NULL;
                   1055:
                   1056:                                        DSA_get0_key(dsa, &pub_key, NULL);
                   1057:
                   1058:                                        BN_print(STDout, pub_key);
                   1059:                                } else
1.20      inoguchi 1060:                                        BIO_printf(STDout,
                   1061:                                            "Wrong Algorithm type");
1.1       jsing    1062:                                BIO_printf(STDout, "\n");
1.31      tb       1063:                        } else if (cfg.pubkey == i) {
1.1       jsing    1064:                                EVP_PKEY *pkey;
                   1065:
1.28      tb       1066:                                pkey = X509_get0_pubkey(x);
1.1       jsing    1067:                                if (pkey == NULL) {
1.20      inoguchi 1068:                                        BIO_printf(bio_err,
                   1069:                                            "Error getting public key\n");
1.1       jsing    1070:                                        ERR_print_errors(bio_err);
                   1071:                                        goto end;
                   1072:                                }
                   1073:                                PEM_write_bio_PUBKEY(STDout, pkey);
1.31      tb       1074:                        } else if (cfg.C == i) {
1.1       jsing    1075:                                unsigned char *d;
                   1076:                                char *m;
                   1077:                                int y, z;
                   1078:
1.23      inoguchi 1079:                                m = X509_NAME_oneline(X509_get_subject_name(x),
1.1       jsing    1080:                                    buf, sizeof buf);
1.23      inoguchi 1081:                                if (m == NULL)
                   1082:                                        goto end;
1.1       jsing    1083:                                BIO_printf(STDout, "/* subject:%s */\n", buf);
1.20      inoguchi 1084:                                m = X509_NAME_oneline(X509_get_issuer_name(x),
                   1085:                                    buf, sizeof buf);
1.23      inoguchi 1086:                                if (m == NULL)
                   1087:                                        goto end;
1.1       jsing    1088:                                BIO_printf(STDout, "/* issuer :%s */\n", buf);
                   1089:
                   1090:                                z = i2d_X509(x, NULL);
1.23      inoguchi 1091:                                if (z < 0)
                   1092:                                        goto end;
                   1093:
1.1       jsing    1094:                                m = malloc(z);
1.8       bcook    1095:                                if (m == NULL) {
                   1096:                                        BIO_printf(bio_err, "out of mem\n");
                   1097:                                        goto end;
                   1098:                                }
1.1       jsing    1099:
                   1100:                                d = (unsigned char *) m;
                   1101:                                z = i2d_X509_NAME(X509_get_subject_name(x), &d);
1.23      inoguchi 1102:                                if (z < 0) {
                   1103:                                        free(m);
                   1104:                                        goto end;
                   1105:                                }
1.20      inoguchi 1106:                                BIO_printf(STDout,
                   1107:                                    "unsigned char XXX_subject_name[%d]={\n", z);
1.1       jsing    1108:                                d = (unsigned char *) m;
                   1109:                                for (y = 0; y < z; y++) {
                   1110:                                        BIO_printf(STDout, "0x%02X,", d[y]);
                   1111:                                        if ((y & 0x0f) == 0x0f)
                   1112:                                                BIO_printf(STDout, "\n");
                   1113:                                }
                   1114:                                if (y % 16 != 0)
                   1115:                                        BIO_printf(STDout, "\n");
                   1116:                                BIO_printf(STDout, "};\n");
                   1117:
                   1118:                                z = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), &d);
1.23      inoguchi 1119:                                if (z < 0) {
                   1120:                                        free(m);
                   1121:                                        goto end;
                   1122:                                }
1.20      inoguchi 1123:                                BIO_printf(STDout,
                   1124:                                    "unsigned char XXX_public_key[%d]={\n", z);
1.1       jsing    1125:                                d = (unsigned char *) m;
                   1126:                                for (y = 0; y < z; y++) {
                   1127:                                        BIO_printf(STDout, "0x%02X,", d[y]);
                   1128:                                        if ((y & 0x0f) == 0x0f)
                   1129:                                                BIO_printf(STDout, "\n");
                   1130:                                }
                   1131:                                if (y % 16 != 0)
                   1132:                                        BIO_printf(STDout, "\n");
                   1133:                                BIO_printf(STDout, "};\n");
                   1134:
                   1135:                                z = i2d_X509(x, &d);
1.23      inoguchi 1136:                                if (z < 0) {
                   1137:                                        free(m);
                   1138:                                        goto end;
                   1139:                                }
1.20      inoguchi 1140:                                BIO_printf(STDout,
                   1141:                                    "unsigned char XXX_certificate[%d]={\n", z);
1.1       jsing    1142:                                d = (unsigned char *) m;
                   1143:                                for (y = 0; y < z; y++) {
                   1144:                                        BIO_printf(STDout, "0x%02X,", d[y]);
                   1145:                                        if ((y & 0x0f) == 0x0f)
                   1146:                                                BIO_printf(STDout, "\n");
                   1147:                                }
                   1148:                                if (y % 16 != 0)
                   1149:                                        BIO_printf(STDout, "\n");
                   1150:                                BIO_printf(STDout, "};\n");
                   1151:
                   1152:                                free(m);
1.31      tb       1153:                        } else if (cfg.text == i) {
                   1154:                                if(!X509_print_ex(STDout, x, cfg.nmflag,
                   1155:                                    cfg.certflag))
1.23      inoguchi 1156:                                        goto end;
1.31      tb       1157:                        } else if (cfg.startdate == i) {
1.18      beck     1158:                                ASN1_TIME *nB = X509_get_notBefore(x);
1.32    ! tb       1159:
1.1       jsing    1160:                                BIO_puts(STDout, "notBefore=");
1.20      inoguchi 1161:                                if (ASN1_time_parse(nB->data, nB->length, NULL,
                   1162:                                    0) == -1)
                   1163:                                        BIO_puts(STDout,
                   1164:                                            "INVALID RFC5280 TIME");
1.18      beck     1165:                                else
                   1166:                                        ASN1_TIME_print(STDout, nB);
1.1       jsing    1167:                                BIO_puts(STDout, "\n");
1.31      tb       1168:                        } else if (cfg.enddate == i) {
1.18      beck     1169:                                ASN1_TIME *nA = X509_get_notAfter(x);
1.32    ! tb       1170:
1.1       jsing    1171:                                BIO_puts(STDout, "notAfter=");
1.20      inoguchi 1172:                                if (ASN1_time_parse(nA->data, nA->length, NULL,
                   1173:                                    0) == -1)
                   1174:                                        BIO_puts(STDout,
                   1175:                                            "INVALID RFC5280 TIME");
1.18      beck     1176:                                else
                   1177:                                        ASN1_TIME_print(STDout, nA);
1.1       jsing    1178:                                BIO_puts(STDout, "\n");
1.31      tb       1179:                        } else if (cfg.fingerprint == i) {
1.1       jsing    1180:                                int j;
                   1181:                                unsigned int n;
                   1182:                                unsigned char md[EVP_MAX_MD_SIZE];
1.31      tb       1183:                                const EVP_MD *fdig = cfg.digest;
1.1       jsing    1184:
1.21      inoguchi 1185:                                if (fdig == NULL)
1.17      jsg      1186:                                        fdig = EVP_sha256();
1.1       jsing    1187:
                   1188:                                if (!X509_digest(x, fdig, md, &n)) {
                   1189:                                        BIO_printf(bio_err, "out of memory\n");
                   1190:                                        goto end;
                   1191:                                }
                   1192:                                BIO_printf(STDout, "%s Fingerprint=",
                   1193:                                    OBJ_nid2sn(EVP_MD_type(fdig)));
                   1194:                                for (j = 0; j < (int) n; j++) {
                   1195:                                        BIO_printf(STDout, "%02X%c", md[j],
                   1196:                                            (j + 1 == (int)n) ? '\n' : ':');
                   1197:                                }
1.20      inoguchi 1198:
1.1       jsing    1199:                        /* should be in the library */
1.32    ! tb       1200:                        } else if (cfg.sign_flag == i && cfg.x509req == 0) {
1.1       jsing    1201:                                BIO_printf(bio_err, "Getting Private key\n");
                   1202:                                if (Upkey == NULL) {
1.32    ! tb       1203:                                        Upkey = load_key(bio_err, cfg.keyfile,
1.31      tb       1204:                                            cfg.keyformat, 0, passin,
1.20      inoguchi 1205:                                            "Private key");
1.1       jsing    1206:                                        if (Upkey == NULL)
                   1207:                                                goto end;
                   1208:                                }
1.31      tb       1209:                                if (!sign(x, Upkey, cfg.days,
                   1210:                                    cfg.clrext, cfg.digest,
                   1211:                                    extconf, cfg.extsect))
1.1       jsing    1212:                                        goto end;
1.31      tb       1213:                        } else if (cfg.CA_flag == i) {
1.1       jsing    1214:                                BIO_printf(bio_err, "Getting CA Private Key\n");
1.31      tb       1215:                                if (cfg.CAkeyfile != NULL) {
1.32    ! tb       1216:                                        CApkey = load_key(bio_err, cfg.CAkeyfile,
1.31      tb       1217:                                            cfg.CAkeyformat, 0, passin,
1.20      inoguchi 1218:                                            "CA Private Key");
1.1       jsing    1219:                                        if (CApkey == NULL)
                   1220:                                                goto end;
                   1221:                                }
1.32    ! tb       1222:                                if (!x509_certify(ctx, cfg.CAfile, cfg.digest,
        !          1223:                                    x, xca, CApkey, cfg.sigopts, cfg.CAserial,
        !          1224:                                    cfg.CA_createserial, cfg.days, cfg.clrext,
        !          1225:                                    extconf, cfg.extsect, cfg.sno))
1.1       jsing    1226:                                        goto end;
1.31      tb       1227:                        } else if (cfg.x509req == i) {
1.1       jsing    1228:                                EVP_PKEY *pk;
                   1229:
1.20      inoguchi 1230:                                BIO_printf(bio_err,
                   1231:                                    "Getting request Private Key\n");
1.31      tb       1232:                                if (cfg.keyfile == NULL) {
1.20      inoguchi 1233:                                        BIO_printf(bio_err,
                   1234:                                            "no request key file specified\n");
1.1       jsing    1235:                                        goto end;
                   1236:                                } else {
1.32    ! tb       1237:                                        pk = load_key(bio_err, cfg.keyfile,
1.31      tb       1238:                                            cfg.keyformat, 0, passin,
1.20      inoguchi 1239:                                            "request key");
1.1       jsing    1240:                                        if (pk == NULL)
                   1241:                                                goto end;
                   1242:                                }
                   1243:
1.20      inoguchi 1244:                                BIO_printf(bio_err,
                   1245:                                    "Generating certificate request\n");
1.1       jsing    1246:
1.31      tb       1247:                                rq = X509_to_X509_REQ(x, pk, cfg.digest);
1.1       jsing    1248:                                EVP_PKEY_free(pk);
                   1249:                                if (rq == NULL) {
                   1250:                                        ERR_print_errors(bio_err);
                   1251:                                        goto end;
                   1252:                                }
1.31      tb       1253:                                if (!cfg.noout) {
1.23      inoguchi 1254:                                        if (!X509_REQ_print(out, rq))
                   1255:                                                goto end;
                   1256:                                        if (!PEM_write_bio_X509_REQ(out, rq))
                   1257:                                                goto end;
1.1       jsing    1258:                                }
1.31      tb       1259:                                cfg.noout = 1;
                   1260:                        } else if (cfg.ocspid == i) {
1.23      inoguchi 1261:                                if (!X509_ocspid_print(out, x))
                   1262:                                        goto end;
1.1       jsing    1263:                        }
                   1264:                }
                   1265:        }
1.31      tb       1266:        if (cfg.checkend) {
                   1267:                time_t tcheck = time(NULL) + cfg.checkoffset;
1.18      beck     1268:                int timecheck = X509_cmp_time(X509_get_notAfter(x), &tcheck);
                   1269:                if (timecheck == 0) {
                   1270:                        BIO_printf(out, "Certificate expiry time is invalid\n");
                   1271:                        ret = 1;
                   1272:                } else if (timecheck < 0) {
1.1       jsing    1273:                        BIO_printf(out, "Certificate will expire\n");
                   1274:                        ret = 1;
                   1275:                } else {
                   1276:                        BIO_printf(out, "Certificate will not expire\n");
                   1277:                        ret = 0;
                   1278:                }
                   1279:                goto end;
                   1280:        }
1.31      tb       1281:        if (cfg.noout) {
1.1       jsing    1282:                ret = 0;
                   1283:                goto end;
                   1284:        }
1.31      tb       1285:        if (cfg.outformat == FORMAT_ASN1)
1.1       jsing    1286:                i = i2d_X509_bio(out, x);
1.31      tb       1287:        else if (cfg.outformat == FORMAT_PEM) {
                   1288:                if (cfg.trustout)
1.1       jsing    1289:                        i = PEM_write_bio_X509_AUX(out, x);
                   1290:                else
                   1291:                        i = PEM_write_bio_X509(out, x);
                   1292:        } else {
1.20      inoguchi 1293:                BIO_printf(bio_err,
                   1294:                    "bad output format specified for outfile\n");
1.1       jsing    1295:                goto end;
                   1296:        }
                   1297:        if (!i) {
                   1298:                BIO_printf(bio_err, "unable to write certificate\n");
                   1299:                ERR_print_errors(bio_err);
                   1300:                goto end;
                   1301:        }
                   1302:        ret = 0;
                   1303:
1.16      jsing    1304:  end:
1.1       jsing    1305:        OBJ_cleanup();
                   1306:        NCONF_free(extconf);
                   1307:        BIO_free_all(out);
                   1308:        BIO_free_all(STDout);
                   1309:        X509_STORE_free(ctx);
                   1310:        X509_REQ_free(req);
                   1311:        X509_free(x);
                   1312:        X509_free(xca);
                   1313:        EVP_PKEY_free(Upkey);
                   1314:        EVP_PKEY_free(CApkey);
1.31      tb       1315:        sk_OPENSSL_STRING_free(cfg.sigopts);
1.1       jsing    1316:        X509_REQ_free(rq);
1.31      tb       1317:        ASN1_INTEGER_free(cfg.sno);
                   1318:        sk_ASN1_OBJECT_pop_free(cfg.trust, ASN1_OBJECT_free);
                   1319:        sk_ASN1_OBJECT_pop_free(cfg.reject, ASN1_OBJECT_free);
1.1       jsing    1320:        free(passin);
                   1321:
                   1322:        return (ret);
                   1323: }
                   1324:
                   1325: static ASN1_INTEGER *
                   1326: x509_load_serial(char *CAfile, char *serialfile, int create)
                   1327: {
                   1328:        char *buf = NULL, *p;
                   1329:        ASN1_INTEGER *bs = NULL;
                   1330:        BIGNUM *serial = NULL;
                   1331:        size_t len;
                   1332:
                   1333:        len = ((serialfile == NULL) ? (strlen(CAfile) + strlen(POSTFIX) + 1) :
                   1334:            (strlen(serialfile))) + 1;
                   1335:        buf = malloc(len);
                   1336:        if (buf == NULL) {
                   1337:                BIO_printf(bio_err, "out of mem\n");
                   1338:                goto end;
                   1339:        }
                   1340:        if (serialfile == NULL) {
                   1341:                strlcpy(buf, CAfile, len);
                   1342:                for (p = buf; *p; p++)
                   1343:                        if (*p == '.') {
                   1344:                                *p = '\0';
                   1345:                                break;
                   1346:                        }
                   1347:                strlcat(buf, POSTFIX, len);
                   1348:        } else
                   1349:                strlcpy(buf, serialfile, len);
                   1350:
                   1351:        serial = load_serial(buf, create, NULL);
                   1352:        if (serial == NULL)
                   1353:                goto end;
                   1354:
                   1355:        if (!BN_add_word(serial, 1)) {
                   1356:                BIO_printf(bio_err, "add_word failure\n");
                   1357:                goto end;
                   1358:        }
                   1359:        if (!save_serial(buf, NULL, serial, &bs))
                   1360:                goto end;
                   1361:
1.16      jsing    1362:  end:
1.1       jsing    1363:        free(buf);
                   1364:        BN_free(serial);
                   1365:
                   1366:        return bs;
                   1367: }
                   1368:
                   1369: static int
                   1370: x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, X509 *x,
                   1371:     X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts,
                   1372:     char *serialfile, int create, int days, int clrext, CONF *conf,
                   1373:     char *section, ASN1_INTEGER *sno)
                   1374: {
                   1375:        int ret = 0;
                   1376:        ASN1_INTEGER *bs = NULL;
1.25      tb       1377:        X509_STORE_CTX *xsc = NULL;
1.1       jsing    1378:        EVP_PKEY *upkey;
                   1379:
1.29      tb       1380:        upkey = X509_get0_pubkey(xca);
1.23      inoguchi 1381:        if (upkey == NULL)
                   1382:                goto end;
1.1       jsing    1383:        EVP_PKEY_copy_parameters(upkey, pkey);
                   1384:
1.25      tb       1385:        if ((xsc = X509_STORE_CTX_new()) == NULL)
                   1386:                goto end;
                   1387:        if (!X509_STORE_CTX_init(xsc, ctx, x, NULL)) {
1.1       jsing    1388:                BIO_printf(bio_err, "Error initialising X509 store\n");
                   1389:                goto end;
                   1390:        }
1.21      inoguchi 1391:        if (sno != NULL)
1.1       jsing    1392:                bs = sno;
1.21      inoguchi 1393:        else if ((bs = x509_load_serial(CAfile, serialfile, create)) == NULL)
1.1       jsing    1394:                goto end;
                   1395:
                   1396: /*     if (!X509_STORE_add_cert(ctx,x)) goto end;*/
                   1397:
                   1398:        /*
                   1399:         * NOTE: this certificate can/should be self signed, unless it was a
                   1400:         * certificate request in which case it is not.
                   1401:         */
1.25      tb       1402:        X509_STORE_CTX_set_cert(xsc, x);
                   1403:        X509_STORE_CTX_set_flags(xsc, X509_V_FLAG_CHECK_SS_SIGNATURE);
1.31      tb       1404:        if (!cfg.reqfile && X509_verify_cert(xsc) <= 0)
1.1       jsing    1405:                goto end;
                   1406:
                   1407:        if (!X509_check_private_key(xca, pkey)) {
1.20      inoguchi 1408:                BIO_printf(bio_err,
                   1409:                    "CA certificate and CA private key do not match\n");
1.1       jsing    1410:                goto end;
                   1411:        }
                   1412:        if (!X509_set_issuer_name(x, X509_get_subject_name(xca)))
                   1413:                goto end;
                   1414:        if (!X509_set_serialNumber(x, bs))
                   1415:                goto end;
                   1416:
                   1417:        if (X509_gmtime_adj(X509_get_notBefore(x), 0L) == NULL)
                   1418:                goto end;
                   1419:
                   1420:        /* hardwired expired */
                   1421:        if (X509_time_adj_ex(X509_get_notAfter(x), days, 0, NULL) == NULL)
                   1422:                goto end;
                   1423:
                   1424:        if (clrext) {
1.23      inoguchi 1425:                while (X509_get_ext_count(x) > 0) {
                   1426:                        if (X509_delete_ext(x, 0) == NULL)
                   1427:                                goto end;
                   1428:                }
1.1       jsing    1429:        }
1.21      inoguchi 1430:        if (conf != NULL) {
1.1       jsing    1431:                X509V3_CTX ctx2;
1.23      inoguchi 1432:                if (!X509_set_version(x, 2))    /* version 3 certificate */
                   1433:                        goto end;
1.1       jsing    1434:                X509V3_set_ctx(&ctx2, xca, x, NULL, NULL, 0);
                   1435:                X509V3_set_nconf(&ctx2, conf);
                   1436:                if (!X509V3_EXT_add_nconf(conf, &ctx2, section, x))
                   1437:                        goto end;
                   1438:        }
                   1439:        if (!do_X509_sign(bio_err, x, pkey, digest, sigopts))
                   1440:                goto end;
1.23      inoguchi 1441:
1.1       jsing    1442:        ret = 1;
1.16      jsing    1443:  end:
1.25      tb       1444:        X509_STORE_CTX_free(xsc);
1.1       jsing    1445:        if (!ret)
                   1446:                ERR_print_errors(bio_err);
1.21      inoguchi 1447:        if (sno == NULL)
1.1       jsing    1448:                ASN1_INTEGER_free(bs);
                   1449:        return ret;
                   1450: }
                   1451:
                   1452: static int
                   1453: callb(int ok, X509_STORE_CTX *ctx)
                   1454: {
                   1455:        int err;
                   1456:        X509 *err_cert;
                   1457:
                   1458:        /*
                   1459:         * it is ok to use a self signed certificate This case will catch
                   1460:         * both the initial ok == 0 and the final ok == 1 calls to this
                   1461:         * function
                   1462:         */
                   1463:        err = X509_STORE_CTX_get_error(ctx);
                   1464:        if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
                   1465:                return 1;
                   1466:
                   1467:        /*
                   1468:         * BAD we should have gotten an error.  Normally if everything worked
                   1469:         * X509_STORE_CTX_get_error(ctx) will still be set to
                   1470:         * DEPTH_ZERO_SELF_....
                   1471:         */
                   1472:        if (ok) {
1.20      inoguchi 1473:                BIO_printf(bio_err,
                   1474:                    "error with certificate to be certified - should be self signed\n");
1.1       jsing    1475:                return 0;
                   1476:        } else {
                   1477:                err_cert = X509_STORE_CTX_get_current_cert(ctx);
                   1478:                print_name(bio_err, NULL, X509_get_subject_name(err_cert), 0);
1.20      inoguchi 1479:                BIO_printf(bio_err,
                   1480:                    "error with certificate - error %d at depth %d\n%s\n",
1.1       jsing    1481:                    err, X509_STORE_CTX_get_error_depth(ctx),
                   1482:                    X509_verify_cert_error_string(err));
                   1483:                return 1;
                   1484:        }
                   1485: }
                   1486:
                   1487: /* self sign */
                   1488: static int
                   1489: sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest,
                   1490:     CONF *conf, char *section)
                   1491: {
                   1492:        EVP_PKEY *pktmp;
                   1493:
1.29      tb       1494:        pktmp = X509_get0_pubkey(x);
1.23      inoguchi 1495:        if (pktmp == NULL)
                   1496:                goto err;
1.1       jsing    1497:        EVP_PKEY_copy_parameters(pktmp, pkey);
                   1498:        EVP_PKEY_save_parameters(pktmp, 1);
                   1499:
                   1500:        if (!X509_set_issuer_name(x, X509_get_subject_name(x)))
                   1501:                goto err;
                   1502:        if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL)
                   1503:                goto err;
                   1504:
                   1505:        /* Lets just make it 12:00am GMT, Jan 1 1970 */
                   1506:        /* memcpy(x->cert_info->validity->notBefore,"700101120000Z",13); */
                   1507:        /* 28 days to be certified */
                   1508:
                   1509:        if (X509_gmtime_adj(X509_get_notAfter(x),
                   1510:            (long) 60 * 60 * 24 * days) == NULL)
                   1511:                goto err;
                   1512:
                   1513:        if (!X509_set_pubkey(x, pkey))
                   1514:                goto err;
                   1515:        if (clrext) {
1.23      inoguchi 1516:                while (X509_get_ext_count(x) > 0) {
                   1517:                        if (X509_delete_ext(x, 0) == NULL)
                   1518:                                goto err;
                   1519:                }
1.1       jsing    1520:        }
1.21      inoguchi 1521:        if (conf != NULL) {
1.1       jsing    1522:                X509V3_CTX ctx;
1.23      inoguchi 1523:                if (!X509_set_version(x, 2))    /* version 3 certificate */
                   1524:                        goto err;
1.1       jsing    1525:                X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0);
                   1526:                X509V3_set_nconf(&ctx, conf);
                   1527:                if (!X509V3_EXT_add_nconf(conf, &ctx, section, x))
                   1528:                        goto err;
                   1529:        }
                   1530:        if (!X509_sign(x, pkey, digest))
                   1531:                goto err;
1.20      inoguchi 1532:
1.1       jsing    1533:        return 1;
                   1534:
1.16      jsing    1535:  err:
1.1       jsing    1536:        ERR_print_errors(bio_err);
                   1537:        return 0;
                   1538: }
                   1539:
                   1540: static int
                   1541: purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt)
                   1542: {
                   1543:        int id, i, idret;
                   1544:        char *pname;
                   1545:
                   1546:        id = X509_PURPOSE_get_id(pt);
                   1547:        pname = X509_PURPOSE_get0_name(pt);
                   1548:        for (i = 0; i < 2; i++) {
                   1549:                idret = X509_check_purpose(cert, id, i);
                   1550:                BIO_printf(bio, "%s%s : ", pname, i ? " CA" : "");
                   1551:                if (idret == 1)
                   1552:                        BIO_printf(bio, "Yes\n");
                   1553:                else if (idret == 0)
                   1554:                        BIO_printf(bio, "No\n");
                   1555:                else
                   1556:                        BIO_printf(bio, "Yes (WARNING code=%d)\n", idret);
                   1557:        }
                   1558:        return 1;
                   1559: }