Annotation of embedaddon/axTLS/ssl/p12.c, revision 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:  * Process PKCS#8/PKCS#12 keys.
        !            33:  *
        !            34:  * The decoding of a PKCS#12 key is fairly specific - this code was tested on a
        !            35:  * key generated with:
        !            36:  *
        !            37:  * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
        !            38:  * -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128 
        !            39:  * -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd
        !            40:  *
        !            41:  * or with a certificate chain:
        !            42:  *
        !            43:  * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
        !            44:  * -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe
        !            45:  * PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd
        !            46:  *
        !            47:  * Note that the PBE has to be specified with PBE-SHA1-RC4-128. The
        !            48:  * private/public keys/certs have to use RSA encryption. Both the integrity
        !            49:  * and privacy passwords are the same.
        !            50:  *
        !            51:  * The PKCS#8 files were generated with something like:
        !            52:  *
        !            53:  * PEM format:
        !            54:  * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1
        !            55:  * PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8
        !            56:  *
        !            57:  * DER format:
        !            58:  * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER
        !            59:  * -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8
        !            60:  */
        !            61: 
        !            62: #include <stdlib.h>
        !            63: #include <string.h>
        !            64: #include <stdio.h>
        !            65: #include "os_port.h"
        !            66: #include "ssl.h"
        !            67: 
        !            68: /* all commented out if not used */
        !            69: #ifdef CONFIG_SSL_USE_PKCS12
        !            70: 
        !            71: #define BLOCK_SIZE          64
        !            72: #define PKCS12_KEY_ID       1
        !            73: #define PKCS12_IV_ID        2
        !            74: #define PKCS12_MAC_ID       3
        !            75: 
        !            76: static char *make_uni_pass(const char *password, int *uni_pass_len);
        !            77: static int p8_decrypt(const char *uni_pass, int uni_pass_len, 
        !            78:                         const uint8_t *salt, int iter, 
        !            79:                         uint8_t *priv_key, int priv_key_len, int id);
        !            80: static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key);
        !            81: static int get_pbe_params(uint8_t *buf, int *offset, 
        !            82:         const uint8_t **salt, int *iterations);
        !            83: 
        !            84: /*
        !            85:  * Take a raw pkcs8 block and then decrypt it and turn it into a normal key.
        !            86:  */
        !            87: int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
        !            88: {
        !            89:     uint8_t *buf = ssl_obj->buf;
        !            90:     int len, offset = 0;
        !            91:     int iterations;
        !            92:     int ret = SSL_NOT_OK;
        !            93:     uint8_t *version = NULL;
        !            94:     const uint8_t *salt;
        !            95:     uint8_t *priv_key;
        !            96:     int uni_pass_len;
        !            97:     char *uni_pass = make_uni_pass(password, &uni_pass_len);
        !            98: 
        !            99:     if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
        !           100:     {
        !           101: #ifdef CONFIG_SSL_FULL_MODE
        !           102:         printf("Error: Invalid p8 ASN.1 file\n");
        !           103: #endif
        !           104:         goto error;
        !           105:     }
        !           106: 
        !           107:     /* unencrypted key? */
        !           108:     if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0)
        !           109:     {
        !           110:         ret = p8_add_key(ssl_ctx, buf);
        !           111:         goto error;
        !           112:     }
        !           113: 
        !           114:     if (get_pbe_params(buf, &offset, &salt, &iterations) < 0)
        !           115:         goto error;
        !           116: 
        !           117:     if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
        !           118:         goto error;
        !           119: 
        !           120:     priv_key = &buf[offset];
        !           121: 
        !           122:     p8_decrypt(uni_pass, uni_pass_len, salt, 
        !           123:                         iterations, priv_key, len, PKCS12_KEY_ID);
        !           124:     ret = p8_add_key(ssl_ctx, priv_key);
        !           125: 
        !           126: error:
        !           127:     free(version);
        !           128:     free(uni_pass);
        !           129:     return ret;
        !           130: }
        !           131: 
        !           132: /*
        !           133:  * Take the unencrypted pkcs8 and turn it into a private key 
        !           134:  */
        !           135: static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key)
        !           136: {
        !           137:     uint8_t *buf = priv_key;
        !           138:     int len, offset = 0;
        !           139:     int ret = SSL_NOT_OK;
        !           140: 
        !           141:     /* Skip the preamble and go straight to the private key.
        !           142:        We only support rsaEncryption (1.2.840.113549.1.1.1)  */
        !           143:     if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           144:             asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
        !           145:             asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           146:             (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
        !           147:         goto error;
        !           148: 
        !           149:     ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx);
        !           150: 
        !           151: error:
        !           152:     return ret;
        !           153: }
        !           154: 
        !           155: /*
        !           156:  * Create the unicode password 
        !           157:  */
        !           158: static char *make_uni_pass(const char *password, int *uni_pass_len)
        !           159: {
        !           160:     int pass_len = 0, i;
        !           161:     char *uni_pass;
        !           162: 
        !           163:     if (password == NULL)
        !           164:     {
        !           165:         password = "";
        !           166:     }
        !           167: 
        !           168:     uni_pass = (char *)malloc((strlen(password)+1)*2);
        !           169: 
        !           170:     /* modify the password into a unicode version */
        !           171:     for (i = 0; i < (int)strlen(password); i++)
        !           172:     {
        !           173:         uni_pass[pass_len++] = 0;
        !           174:         uni_pass[pass_len++] = password[i];
        !           175:     }
        !           176: 
        !           177:     uni_pass[pass_len++] = 0;       /* null terminate */
        !           178:     uni_pass[pass_len++] = 0;
        !           179:     *uni_pass_len = pass_len;
        !           180:     return uni_pass;
        !           181: }
        !           182: 
        !           183: /*
        !           184:  * Decrypt a pkcs8 block.
        !           185:  */
        !           186: static int p8_decrypt(const char *uni_pass, int uni_pass_len,
        !           187:                         const uint8_t *salt, int iter, 
        !           188:                         uint8_t *priv_key, int priv_key_len, int id)
        !           189: {
        !           190:     uint8_t p[BLOCK_SIZE*2];
        !           191:     uint8_t d[BLOCK_SIZE];
        !           192:     uint8_t Ai[SHA1_SIZE];
        !           193:     SHA1_CTX sha_ctx;
        !           194:     RC4_CTX rc4_ctx;
        !           195:     int i;
        !           196: 
        !           197:     for (i = 0; i < BLOCK_SIZE; i++)
        !           198:     {
        !           199:         p[i] = salt[i % SALT_SIZE];
        !           200:         p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len];
        !           201:         d[i] = id;
        !           202:     }
        !           203: 
        !           204:     /* get the key - no IV since we are using RC4 */
        !           205:     SHA1_Init(&sha_ctx);
        !           206:     SHA1_Update(&sha_ctx, d, sizeof(d));
        !           207:     SHA1_Update(&sha_ctx, p, sizeof(p));
        !           208:     SHA1_Final(Ai, &sha_ctx);
        !           209: 
        !           210:     for (i = 1; i < iter; i++)
        !           211:     {
        !           212:         SHA1_Init(&sha_ctx);
        !           213:         SHA1_Update(&sha_ctx, Ai, SHA1_SIZE);
        !           214:         SHA1_Final(Ai, &sha_ctx);
        !           215:     }
        !           216: 
        !           217:     /* do the decryption */
        !           218:     if (id == PKCS12_KEY_ID)
        !           219:     {
        !           220:         RC4_setup(&rc4_ctx, Ai, 16);
        !           221:         RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len);
        !           222:     }
        !           223:     else  /* MAC */
        !           224:         memcpy(priv_key, Ai, SHA1_SIZE);
        !           225: 
        !           226:     return 0;
        !           227: }
        !           228: 
        !           229: /*
        !           230:  * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s)
        !           231:  * and keys.
        !           232:  */
        !           233: int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
        !           234: {
        !           235:     uint8_t *buf = ssl_obj->buf;
        !           236:     int len, iterations, auth_safes_start, 
        !           237:               auth_safes_end, auth_safes_len, key_offset, offset = 0;
        !           238:     int all_certs = 0;
        !           239:     uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac;
        !           240:     uint8_t key[SHA1_SIZE];
        !           241:     uint8_t mac[SHA1_SIZE];
        !           242:     const uint8_t *salt;
        !           243:     int uni_pass_len, ret = SSL_OK;
        !           244:     char *uni_pass = make_uni_pass(password, &uni_pass_len);
        !           245:     static const uint8_t pkcs_data[] = /* pkc7 data */
        !           246:         { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 };
        !           247:     static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */
        !           248:         { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 };
        !           249:     static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */
        !           250:         { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 };
        !           251: 
        !           252:     if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
        !           253:     {
        !           254: #ifdef CONFIG_SSL_FULL_MODE
        !           255:         printf("Error: Invalid p12 ASN.1 file\n");
        !           256: #endif
        !           257:         goto error;
        !           258:     }
        !           259: 
        !           260:     if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3)
        !           261:     {
        !           262:         ret = SSL_ERROR_INVALID_VERSION;
        !           263:         goto error;
        !           264:     }
        !           265: 
        !           266:     /* remove all the boring pcks7 bits */
        !           267:     if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || 
        !           268:                 (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
        !           269:                 len != sizeof(pkcs_data) || 
        !           270:                 memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
        !           271:         goto error;
        !           272: 
        !           273:     offset += len;
        !           274: 
        !           275:     if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
        !           276:             asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0)
        !           277:         goto error;
        !           278: 
        !           279:     /* work out the MAC start/end points (done on AuthSafes) */
        !           280:     auth_safes_start = offset;
        !           281:     auth_safes_end = offset;
        !           282:     if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0)
        !           283:         goto error;
        !           284: 
        !           285:     auth_safes_len = auth_safes_end - auth_safes_start;
        !           286:     auth_safes = malloc(auth_safes_len);
        !           287: 
        !           288:     memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len);
        !           289: 
        !           290:     if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           291:             asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           292:             (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
        !           293:             (len != sizeof(pkcs_encrypted) || 
        !           294:             memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted))))
        !           295:         goto error;
        !           296: 
        !           297:     offset += len;
        !           298: 
        !           299:     if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
        !           300:             asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           301:             asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
        !           302:             asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           303:             (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
        !           304:             len != sizeof(pkcs_data) || 
        !           305:             memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
        !           306:         goto error;
        !           307: 
        !           308:     offset += len;
        !           309: 
        !           310:     /* work out the salt for the certificate */
        !           311:     if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
        !           312:             (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0)
        !           313:         goto error;
        !           314: 
        !           315:     /* decrypt the certificate */
        !           316:     cert = &buf[offset];
        !           317:     if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, 
        !           318:                             len, PKCS12_KEY_ID)) < 0)
        !           319:         goto error;
        !           320: 
        !           321:     offset += len;
        !           322: 
        !           323:     /* load the certificate */
        !           324:     key_offset = 0;
        !           325:     all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE);
        !           326: 
        !           327:     /* keep going until all certs are loaded */
        !           328:     while (key_offset < all_certs)
        !           329:     {
        !           330:         int cert_offset = key_offset;
        !           331: 
        !           332:         if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 ||
        !           333:                 asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
        !           334:                 asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
        !           335:                 asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
        !           336:                 asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
        !           337:                 asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
        !           338:                 asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
        !           339:                 (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0)
        !           340:             goto error;
        !           341: 
        !           342:         if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0)
        !           343:             goto error;
        !           344: 
        !           345:         key_offset = cert_offset;
        !           346:     }
        !           347: 
        !           348:     if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           349:             (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
        !           350:             len != sizeof(pkcs_data) || 
        !           351:             memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
        !           352:         goto error;
        !           353: 
        !           354:     offset += len;
        !           355: 
        !           356:     if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
        !           357:             asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 ||
        !           358:             asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           359:             asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           360:             (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
        !           361:             (len != sizeof(pkcs8_key_bag)) || 
        !           362:             memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag)))
        !           363:         goto error;
        !           364: 
        !           365:     offset += len;
        !           366: 
        !           367:     /* work out the salt for the private key */
        !           368:     if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
        !           369:             asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           370:             get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
        !           371:             (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
        !           372:         goto error;
        !           373: 
        !           374:     /* decrypt the private key */
        !           375:     cert = &buf[offset];
        !           376:     if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, 
        !           377:                             len, PKCS12_KEY_ID)) < 0)
        !           378:         goto error;
        !           379: 
        !           380:     offset += len;
        !           381: 
        !           382:     /* load the private key */
        !           383:     if ((ret = p8_add_key(ssl_ctx, cert)) < 0)
        !           384:         goto error;
        !           385: 
        !           386:     /* miss out on friendly name, local key id etc */
        !           387:     if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0)
        !           388:         goto error;
        !           389: 
        !           390:     /* work out the MAC */
        !           391:     if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           392:             asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           393:             asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
        !           394:             (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 ||
        !           395:             len != SHA1_SIZE)
        !           396:         goto error;
        !           397: 
        !           398:     orig_mac = &buf[offset];
        !           399:     offset += len;
        !           400: 
        !           401:     /* get the salt */
        !           402:     if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8)
        !           403:         goto error;
        !           404: 
        !           405:     salt = &buf[offset];
        !           406: 
        !           407:     /* work out what the mac should be */
        !           408:     if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, 
        !           409:                             key, SHA1_SIZE, PKCS12_MAC_ID)) < 0)
        !           410:         goto error;
        !           411: 
        !           412:     hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac);
        !           413: 
        !           414:     if (memcmp(mac, orig_mac, SHA1_SIZE))
        !           415:     {
        !           416:         ret = SSL_ERROR_INVALID_HMAC;                  
        !           417:         goto error;
        !           418:     }
        !           419: 
        !           420: error:
        !           421:     free(version);
        !           422:     free(uni_pass);
        !           423:     free(auth_safes);
        !           424:     return ret;
        !           425: }
        !           426: 
        !           427: /*
        !           428:  * Retrieve the salt/iteration details from a PBE block.
        !           429:  */
        !           430: static int get_pbe_params(uint8_t *buf, int *offset, 
        !           431:         const uint8_t **salt, int *iterations)
        !           432: {
        !           433:     static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4  */
        !           434:             { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 };
        !           435: 
        !           436:     int i, len;
        !           437:     uint8_t *iter = NULL;
        !           438:     int error_code = SSL_ERROR_NOT_SUPPORTED;
        !           439: 
        !           440:     /* Get the PBE type */
        !           441:     if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
        !           442:             (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
        !           443:         goto error;
        !           444: 
        !           445:     /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1) 
        !           446:        which is the only algorithm we support */
        !           447:     if (len != sizeof(pbeSH1RC4) || 
        !           448:                     memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4)))
        !           449:     {
        !           450: #ifdef CONFIG_SSL_FULL_MODE
        !           451:         printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n");
        !           452: #endif
        !           453:         goto error;
        !           454:     }
        !           455: 
        !           456:     *offset += len;
        !           457: 
        !           458:     if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
        !           459:             (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 || 
        !           460:             len != 8)
        !           461:         goto error;
        !           462: 
        !           463:     *salt = &buf[*offset];
        !           464:     *offset += len;
        !           465: 
        !           466:     if ((len = asn1_get_int(buf, offset, &iter)) < 0)
        !           467:         goto error;
        !           468: 
        !           469:     *iterations = 0;
        !           470:     for (i = 0; i < len; i++)
        !           471:     {
        !           472:         (*iterations) <<= 8;
        !           473:         (*iterations) += iter[i];
        !           474:     }
        !           475: 
        !           476:     free(iter);
        !           477:     error_code = SSL_OK;       /* got here - we are ok */
        !           478: 
        !           479: error:
        !           480:     return error_code;
        !           481: }
        !           482: 
        !           483: #endif

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