Annotation of embedaddon/axTLS/ssl/x509.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 2007, Cameron Rich
                      3:  * 
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Redistribution and use in source and binary forms, with or without 
                      7:  * modification, are permitted provided that the following conditions are met:
                      8:  *
                      9:  * * Redistributions of source code must retain the above copyright notice, 
                     10:  *   this list of conditions and the following disclaimer.
                     11:  * * Redistributions in binary form must reproduce the above copyright notice, 
                     12:  *   this list of conditions and the following disclaimer in the documentation 
                     13:  *   and/or other materials provided with the distribution.
                     14:  * * Neither the name of the axTLS project nor the names of its contributors 
                     15:  *   may be used to endorse or promote products derived from this software 
                     16:  *   without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                     19:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     20:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     21:  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
                     22:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     23:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     24:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
                     25:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
                     26:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
                     27:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
                     28:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     29:  */
                     30: 
                     31: /**
                     32:  * @file x509.c
                     33:  * 
                     34:  * Certificate processing.
                     35:  */
                     36: 
                     37: #include <stdio.h>
                     38: #include <stdlib.h>
                     39: #include <string.h>
                     40: #include <time.h>
                     41: #include "os_port.h"
                     42: #include "crypto_misc.h"
                     43: 
                     44: #ifdef CONFIG_SSL_CERT_VERIFICATION
                     45: /**
                     46:  * Retrieve the signature from a certificate.
                     47:  */
                     48: static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
                     49: {
                     50:     int offset = 0;
                     51:     const uint8_t *ptr = NULL;
                     52: 
                     53:     if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || 
                     54:             asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
                     55:         goto end_get_sig;
                     56: 
                     57:     if (asn1_sig[offset++] != ASN1_OCTET_STRING)
                     58:         goto end_get_sig;
                     59:     *len = get_asn1_length(asn1_sig, &offset);
                     60:     ptr = &asn1_sig[offset];          /* all ok */
                     61: 
                     62: end_get_sig:
                     63:     return ptr;
                     64: }
                     65: 
                     66: #endif
                     67: 
                     68: /**
                     69:  * Construct a new x509 object.
                     70:  * @return 0 if ok. < 0 if there was a problem.
                     71:  */
                     72: int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
                     73: {
                     74:     int begin_tbs, end_tbs;
                     75:     int ret = X509_NOT_OK, offset = 0, cert_size = 0;
                     76:     X509_CTX *x509_ctx;
                     77:     BI_CTX *bi_ctx;
                     78: 
                     79:     *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
                     80:     x509_ctx = *ctx;
                     81: 
                     82:     /* get the certificate size */
                     83:     asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); 
                     84: 
                     85:     if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
                     86:         goto end_cert;
                     87: 
                     88:     begin_tbs = offset;         /* start of the tbs */
                     89:     end_tbs = begin_tbs;        /* work out the end of the tbs */
                     90:     asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
                     91: 
                     92:     if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
                     93:         goto end_cert;
                     94: 
                     95:     if (cert[offset] == ASN1_EXPLICIT_TAG)   /* optional version */
                     96:     {
                     97:         if (asn1_version(cert, &offset, x509_ctx))
                     98:             goto end_cert;
                     99:     }
                    100: 
                    101:     if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ 
                    102:             asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
                    103:         goto end_cert;
                    104: 
                    105:     /* make sure the signature is ok */
                    106:     if (asn1_signature_type(cert, &offset, x509_ctx))
                    107:     {
                    108:         ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
                    109:         goto end_cert;
                    110:     }
                    111: 
                    112:     if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || 
                    113:             asn1_validity(cert, &offset, x509_ctx) ||
                    114:             asn1_name(cert, &offset, x509_ctx->cert_dn) ||
                    115:             asn1_public_key(cert, &offset, x509_ctx))
                    116:     {
                    117:         goto end_cert;
                    118:     }
                    119: 
                    120:     bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
                    121: 
                    122: #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
                    123:     /* use the appropriate signature algorithm (SHA1/MD5/MD2) */
                    124:     if (x509_ctx->sig_type == SIG_TYPE_MD5)
                    125:     {
                    126:         MD5_CTX md5_ctx;
                    127:         uint8_t md5_dgst[MD5_SIZE];
                    128:         MD5_Init(&md5_ctx);
                    129:         MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
                    130:         MD5_Final(md5_dgst, &md5_ctx);
                    131:         x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
                    132:     }
                    133:     else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
                    134:     {
                    135:         SHA1_CTX sha_ctx;
                    136:         uint8_t sha_dgst[SHA1_SIZE];
                    137:         SHA1_Init(&sha_ctx);
                    138:         SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
                    139:         SHA1_Final(sha_dgst, &sha_ctx);
                    140:         x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
                    141:     }
                    142:     else if (x509_ctx->sig_type == SIG_TYPE_MD2)
                    143:     {
                    144:         MD2_CTX md2_ctx;
                    145:         uint8_t md2_dgst[MD2_SIZE];
                    146:         MD2_Init(&md2_ctx);
                    147:         MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
                    148:         MD2_Final(md2_dgst, &md2_ctx);
                    149:         x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
                    150:     }
                    151: 
                    152:     if (cert[offset] == ASN1_V3_DATA)
                    153:     {
                    154:         int suboffset;
                    155: 
                    156:         ++offset;
                    157:         get_asn1_length(cert, &offset);
                    158: 
                    159:         if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)
                    160:         {
                    161:             if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)
                    162:             {
                    163:                 int altlen;
                    164: 
                    165:                 if ((altlen = asn1_next_obj(cert, 
                    166:                                             &suboffset, ASN1_SEQUENCE)) > 0)
                    167:                 {
                    168:                     int endalt = suboffset + altlen;
                    169:                     int totalnames = 0;
                    170: 
                    171:                     while (suboffset < endalt)
                    172:                     {
                    173:                         int type = cert[suboffset++];
                    174:                         int dnslen = get_asn1_length(cert, &suboffset);
                    175: 
                    176:                         if (type == ASN1_CONTEXT_DNSNAME)
                    177:                         {
                    178:                             x509_ctx->subject_alt_dnsnames = (char**)
                    179:                                     realloc(x509_ctx->subject_alt_dnsnames, 
                    180:                                        (totalnames + 2) * sizeof(char*));
                    181:                             x509_ctx->subject_alt_dnsnames[totalnames] = 
                    182:                                     (char*)malloc(dnslen + 1);
                    183:                             x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;
                    184:                             memcpy(x509_ctx->subject_alt_dnsnames[totalnames], 
                    185:                                     cert + suboffset, dnslen);
                    186:                             x509_ctx->subject_alt_dnsnames[
                    187:                                     totalnames][dnslen] = 0;
                    188:                             ++totalnames;
                    189:                         }
                    190: 
                    191:                         suboffset += dnslen;
                    192:                     }
                    193:                 }
                    194:             }
                    195:         }
                    196:     }
                    197: 
                    198:     offset = end_tbs;   /* skip the rest of v3 data */
                    199:     if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || 
                    200:             asn1_signature(cert, &offset, x509_ctx))
                    201:         goto end_cert;
                    202: #endif
                    203:     ret = X509_OK;
                    204: end_cert:
                    205:     if (len)
                    206:     {
                    207:         *len = cert_size;
                    208:     }
                    209: 
                    210:     if (ret)
                    211:     {
                    212: #ifdef CONFIG_SSL_FULL_MODE
                    213:         printf("Error: Invalid X509 ASN.1 file (%s)\n",
                    214:                         x509_display_error(ret));
                    215: #endif
                    216:         x509_free(x509_ctx);
                    217:         *ctx = NULL;
                    218:     }
                    219: 
                    220:     return ret;
                    221: }
                    222: 
                    223: /**
                    224:  * Free an X.509 object's resources.
                    225:  */
                    226: void x509_free(X509_CTX *x509_ctx)
                    227: {
                    228:     X509_CTX *next;
                    229:     int i;
                    230: 
                    231:     if (x509_ctx == NULL)       /* if already null, then don't bother */
                    232:         return;
                    233: 
                    234:     for (i = 0; i < X509_NUM_DN_TYPES; i++)
                    235:     {
                    236:         free(x509_ctx->ca_cert_dn[i]);
                    237:         free(x509_ctx->cert_dn[i]);
                    238:     }
                    239: 
                    240:     free(x509_ctx->signature);
                    241: 
                    242: #ifdef CONFIG_SSL_CERT_VERIFICATION 
                    243:     if (x509_ctx->digest)
                    244:     {
                    245:         bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
                    246:     }
                    247: 
                    248:     if (x509_ctx->subject_alt_dnsnames)
                    249:     {
                    250:         for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)
                    251:             free(x509_ctx->subject_alt_dnsnames[i]);
                    252: 
                    253:         free(x509_ctx->subject_alt_dnsnames);
                    254:     }
                    255: #endif
                    256: 
                    257:     RSA_free(x509_ctx->rsa_ctx);
                    258:     next = x509_ctx->next;
                    259:     free(x509_ctx);
                    260:     x509_free(next);        /* clear the chain */
                    261: }
                    262: 
                    263: #ifdef CONFIG_SSL_CERT_VERIFICATION
                    264: /**
                    265:  * Take a signature and decrypt it.
                    266:  */
                    267: static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
                    268:         bigint *modulus, bigint *pub_exp)
                    269: {
                    270:     int i, size;
                    271:     bigint *decrypted_bi, *dat_bi;
                    272:     bigint *bir = NULL;
                    273:     uint8_t *block = (uint8_t *)alloca(sig_len);
                    274: 
                    275:     /* decrypt */
                    276:     dat_bi = bi_import(ctx, sig, sig_len);
                    277:     ctx->mod_offset = BIGINT_M_OFFSET;
                    278: 
                    279:     /* convert to a normal block */
                    280:     decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
                    281: 
                    282:     bi_export(ctx, decrypted_bi, block, sig_len);
                    283:     ctx->mod_offset = BIGINT_M_OFFSET;
                    284: 
                    285:     i = 10; /* start at the first possible non-padded byte */
                    286:     while (block[i++] && i < sig_len);
                    287:     size = sig_len - i;
                    288: 
                    289:     /* get only the bit we want */
                    290:     if (size > 0)
                    291:     {
                    292:         int len;
                    293:         const uint8_t *sig_ptr = get_signature(&block[i], &len);
                    294: 
                    295:         if (sig_ptr)
                    296:         {
                    297:             bir = bi_import(ctx, sig_ptr, len);
                    298:         }
                    299:     }
                    300: 
                    301:     /* save a few bytes of memory */
                    302:     bi_clear_cache(ctx);
                    303:     return bir;
                    304: }
                    305: 
                    306: /**
                    307:  * Do some basic checks on the certificate chain.
                    308:  *
                    309:  * Certificate verification consists of a number of checks:
                    310:  * - The date of the certificate is after the start date.
                    311:  * - The date of the certificate is before the finish date.
                    312:  * - A root certificate exists in the certificate store.
                    313:  * - That the certificate(s) are not self-signed.
                    314:  * - The certificate chain is valid.
                    315:  * - The signature of the certificate is valid.
                    316:  */
                    317: int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) 
                    318: {
                    319:     int ret = X509_OK, i = 0;
                    320:     bigint *cert_sig;
                    321:     X509_CTX *next_cert = NULL;
                    322:     BI_CTX *ctx = NULL;
                    323:     bigint *mod = NULL, *expn = NULL;
                    324:     int match_ca_cert = 0;
                    325:     struct timeval tv;
                    326:     uint8_t is_self_signed = 0;
                    327: 
                    328:     if (cert == NULL)
                    329:     {
                    330:         ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       
                    331:         goto end_verify;
                    332:     }
                    333: 
                    334:     /* a self-signed certificate that is not in the CA store - use this 
                    335:        to check the signature */
                    336:     if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
                    337:     {
                    338:         is_self_signed = 1;
                    339:         ctx = cert->rsa_ctx->bi_ctx;
                    340:         mod = cert->rsa_ctx->m;
                    341:         expn = cert->rsa_ctx->e;
                    342:     }
                    343: 
                    344:     gettimeofday(&tv, NULL);
                    345: 
                    346:     /* check the not before date */
                    347:     if (tv.tv_sec < cert->not_before)
                    348:     {
                    349:         ret = X509_VFY_ERROR_NOT_YET_VALID;
                    350:         goto end_verify;
                    351:     }
                    352: 
                    353:     /* check the not after date */
                    354:     if (tv.tv_sec > cert->not_after)
                    355:     {
                    356:         ret = X509_VFY_ERROR_EXPIRED;
                    357:         goto end_verify;
                    358:     }
                    359: 
                    360:     next_cert = cert->next;
                    361: 
                    362:     /* last cert in the chain - look for a trusted cert */
                    363:     if (next_cert == NULL)
                    364:     {
                    365:        if (ca_cert_ctx != NULL) 
                    366:        {
                    367:             /* go thu the CA store */
                    368:             while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
                    369:             {
                    370:                 if (asn1_compare_dn(cert->ca_cert_dn,
                    371:                                             ca_cert_ctx->cert[i]->cert_dn) == 0)
                    372:                 {
                    373:                     /* use this CA certificate for signature verification */
                    374:                     match_ca_cert = 1;
                    375:                     ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;
                    376:                     mod = ca_cert_ctx->cert[i]->rsa_ctx->m;
                    377:                     expn = ca_cert_ctx->cert[i]->rsa_ctx->e;
                    378:                     break;
                    379:                 }
                    380: 
                    381:                 i++;
                    382:             }
                    383:         }
                    384: 
                    385:         /* couldn't find a trusted cert (& let self-signed errors 
                    386:            be returned) */
                    387:         if (!match_ca_cert && !is_self_signed)
                    388:         {
                    389:             ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       
                    390:             goto end_verify;
                    391:         }
                    392:     }
                    393:     else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)
                    394:     {
                    395:         /* check the chain */
                    396:         ret = X509_VFY_ERROR_INVALID_CHAIN;
                    397:         goto end_verify;
                    398:     }
                    399:     else /* use the next certificate in the chain for signature verify */
                    400:     {
                    401:         ctx = next_cert->rsa_ctx->bi_ctx;
                    402:         mod = next_cert->rsa_ctx->m;
                    403:         expn = next_cert->rsa_ctx->e;
                    404:     }
                    405: 
                    406:     /* cert is self signed */
                    407:     if (!match_ca_cert && is_self_signed)
                    408:     {
                    409:         ret = X509_VFY_ERROR_SELF_SIGNED;
                    410:         goto end_verify;
                    411:     }
                    412: 
                    413:     /* check the signature */
                    414:     cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, 
                    415:                         bi_clone(ctx, mod), bi_clone(ctx, expn));
                    416: 
                    417:     if (cert_sig && cert->digest)
                    418:     {
                    419:         if (bi_compare(cert_sig, cert->digest) != 0)
                    420:             ret = X509_VFY_ERROR_BAD_SIGNATURE;
                    421: 
                    422: 
                    423:         bi_free(ctx, cert_sig);
                    424:     }
                    425:     else
                    426:     {
                    427:         ret = X509_VFY_ERROR_BAD_SIGNATURE;
                    428:     }
                    429: 
                    430:     if (ret)
                    431:         goto end_verify;
                    432: 
                    433:     /* go down the certificate chain using recursion. */
                    434:     if (next_cert != NULL)
                    435:     {
                    436:         ret = x509_verify(ca_cert_ctx, next_cert);
                    437:     }
                    438: 
                    439: end_verify:
                    440:     return ret;
                    441: }
                    442: #endif
                    443: 
                    444: #if defined (CONFIG_SSL_FULL_MODE)
                    445: /**
                    446:  * Used for diagnostics.
                    447:  */
                    448: static const char *not_part_of_cert = "<Not Part Of Certificate>";
                    449: void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) 
                    450: {
                    451:     if (cert == NULL)
                    452:         return;
                    453: 
                    454:     printf("=== CERTIFICATE ISSUED TO ===\n");
                    455:     printf("Common Name (CN):\t\t");
                    456:     printf("%s\n", cert->cert_dn[X509_COMMON_NAME] ?
                    457:                     cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);
                    458: 
                    459:     printf("Organization (O):\t\t");
                    460:     printf("%s\n", cert->cert_dn[X509_ORGANIZATION] ?
                    461:         cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);
                    462: 
                    463:     printf("Organizational Unit (OU):\t");
                    464:     printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
                    465:         cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
                    466: 
                    467:     printf("=== CERTIFICATE ISSUED BY ===\n");
                    468:     printf("Common Name (CN):\t\t");
                    469:     printf("%s\n", cert->ca_cert_dn[X509_COMMON_NAME] ?
                    470:                     cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);
                    471: 
                    472:     printf("Organization (O):\t\t");
                    473:     printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATION] ?
                    474:         cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);
                    475: 
                    476:     printf("Organizational Unit (OU):\t");
                    477:     printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
                    478:         cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
                    479: 
                    480:     printf("Not Before:\t\t\t%s", ctime(&cert->not_before));
                    481:     printf("Not After:\t\t\t%s", ctime(&cert->not_after));
                    482:     printf("RSA bitsize:\t\t\t%d\n", cert->rsa_ctx->num_octets*8);
                    483:     printf("Sig Type:\t\t\t");
                    484:     switch (cert->sig_type)
                    485:     {
                    486:         case SIG_TYPE_MD5:
                    487:             printf("MD5\n");
                    488:             break;
                    489:         case SIG_TYPE_SHA1:
                    490:             printf("SHA1\n");
                    491:             break;
                    492:         case SIG_TYPE_MD2:
                    493:             printf("MD2\n");
                    494:             break;
                    495:         default:
                    496:             printf("Unrecognized: %d\n", cert->sig_type);
                    497:             break;
                    498:     }
                    499: 
                    500:     if (ca_cert_ctx)
                    501:     {
                    502:         printf("Verify:\t\t\t\t%s\n",
                    503:                 x509_display_error(x509_verify(ca_cert_ctx, cert)));
                    504:     }
                    505: 
                    506: #if 0
                    507:     print_blob("Signature", cert->signature, cert->sig_len);
                    508:     bi_print("Modulus", cert->rsa_ctx->m);
                    509:     bi_print("Pub Exp", cert->rsa_ctx->e);
                    510: #endif
                    511: 
                    512:     if (ca_cert_ctx)
                    513:     {
                    514:         x509_print(cert->next, ca_cert_ctx);
                    515:     }
                    516: 
                    517:     TTY_FLUSH();
                    518: }
                    519: 
                    520: const char * x509_display_error(int error)
                    521: {
                    522:     switch (error)
                    523:     {
                    524:         case X509_OK:
                    525:             return "Certificate verify successful";
                    526: 
                    527:         case X509_NOT_OK:
                    528:             return "X509 not ok";
                    529: 
                    530:         case X509_VFY_ERROR_NO_TRUSTED_CERT:
                    531:             return "No trusted cert is available";
                    532: 
                    533:         case X509_VFY_ERROR_BAD_SIGNATURE:
                    534:             return "Bad signature";
                    535: 
                    536:         case X509_VFY_ERROR_NOT_YET_VALID:
                    537:             return "Cert is not yet valid";
                    538: 
                    539:         case X509_VFY_ERROR_EXPIRED:
                    540:             return "Cert has expired";
                    541: 
                    542:         case X509_VFY_ERROR_SELF_SIGNED:
                    543:             return "Cert is self-signed";
                    544: 
                    545:         case X509_VFY_ERROR_INVALID_CHAIN:
                    546:             return "Chain is invalid (check order of certs)";
                    547: 
                    548:         case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
                    549:             return "Unsupported digest";
                    550: 
                    551:         case X509_INVALID_PRIV_KEY:
                    552:             return "Invalid private key";
                    553: 
                    554:         default:
                    555:             return "Unknown";
                    556:     }
                    557: }
                    558: #endif      /* CONFIG_SSL_FULL_MODE */
                    559: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>