Annotation of embedaddon/axTLS/ssl/gen_cert.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: #include "config.h"
        !            32: 
        !            33: #ifdef CONFIG_SSL_GENERATE_X509_CERT
        !            34: #include <string.h>
        !            35: #include <stdlib.h>
        !            36: #include "os_port.h"
        !            37: #include "ssl.h"
        !            38: 
        !            39: /**
        !            40:  * Generate a basic X.509 certificate
        !            41:  */
        !            42: 
        !            43: static uint8_t set_gen_length(int len, uint8_t *buf, int *offset)
        !            44: {
        !            45:     if (len < 0x80) /* short form */
        !            46:     {
        !            47:         buf[(*offset)++] = len;
        !            48:         return 1;
        !            49:     }
        !            50:     else /* long form */
        !            51:     {
        !            52:         int i, length_bytes = 0;
        !            53: 
        !            54:         if (len & 0x00FF0000)
        !            55:             length_bytes = 3;
        !            56:         else if (len & 0x0000FF00)
        !            57:             length_bytes = 2;
        !            58:         else if (len & 0x000000FF)
        !            59:             length_bytes = 1;
        !            60:             
        !            61:         buf[(*offset)++] = 0x80 + length_bytes;
        !            62: 
        !            63:         for (i = length_bytes-1; i >= 0; i--)
        !            64:         {
        !            65:             buf[*offset+i] = len & 0xFF;
        !            66:             len >>= 8;
        !            67:         }
        !            68: 
        !            69:         *offset += length_bytes;
        !            70:         return length_bytes+1;
        !            71:     }
        !            72: }
        !            73: 
        !            74: static int pre_adjust_with_size(uint8_t type,
        !            75:         int *seq_offset, uint8_t *buf, int *offset)
        !            76: {
        !            77:     buf[(*offset)++] = type;
        !            78:     *seq_offset = *offset;
        !            79:     *offset += 4;   /* fill in later */
        !            80:     return *offset;
        !            81: }
        !            82: 
        !            83: static void adjust_with_size(int seq_size, int seq_start, 
        !            84:                 uint8_t *buf, int *offset)
        !            85: {
        !            86:     uint8_t seq_byte_size; 
        !            87:     int orig_seq_size = seq_size;
        !            88:     int orig_seq_start = seq_start;
        !            89: 
        !            90:     seq_size = *offset-seq_size;
        !            91:     seq_byte_size = set_gen_length(seq_size, buf, &seq_start);
        !            92: 
        !            93:     if (seq_byte_size != 4)
        !            94:     {
        !            95:         memmove(&buf[orig_seq_start+seq_byte_size], 
        !            96:                 &buf[orig_seq_size], seq_size);
        !            97:         *offset -= 4-seq_byte_size;
        !            98:     }
        !            99: }
        !           100: 
        !           101: static void gen_serial_number(uint8_t *buf, int *offset)
        !           102: {
        !           103:     static const uint8_t ser_oid[] = { ASN1_INTEGER, 1, 0x7F };
        !           104:     memcpy(&buf[*offset], ser_oid , sizeof(ser_oid));
        !           105:     *offset += sizeof(ser_oid);
        !           106: }
        !           107: 
        !           108: static void gen_signature_alg(uint8_t *buf, int *offset)
        !           109: {
        !           110:     /* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */
        !           111:     static const uint8_t sig_oid[] = 
        !           112:     {
        !           113:         ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09, 
        !           114:         0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
        !           115:         ASN1_NULL, 0x00
        !           116:     };
        !           117: 
        !           118:     memcpy(&buf[*offset], sig_oid, sizeof(sig_oid));
        !           119:     *offset += sizeof(sig_oid);
        !           120: }
        !           121: 
        !           122: static int gen_dn(const char *name, uint8_t dn_type, 
        !           123:                         uint8_t *buf, int *offset)
        !           124: {
        !           125:     int ret = X509_OK;
        !           126:     int name_size = strlen(name);
        !           127: 
        !           128:     if (name_size > 0x70)    /* just too big */
        !           129:     {
        !           130:         ret = X509_NOT_OK;
        !           131:         goto error;
        !           132:     }
        !           133: 
        !           134:     buf[(*offset)++] = ASN1_SET;
        !           135:     set_gen_length(9+name_size, buf, offset);
        !           136:     buf[(*offset)++] = ASN1_SEQUENCE;
        !           137:     set_gen_length(7+name_size, buf, offset);
        !           138:     buf[(*offset)++] = ASN1_OID;
        !           139:     buf[(*offset)++] = 3;
        !           140:     buf[(*offset)++] = 0x55;
        !           141:     buf[(*offset)++] = 0x04;
        !           142:     buf[(*offset)++] = dn_type;
        !           143:     buf[(*offset)++] = ASN1_PRINTABLE_STR;
        !           144:     buf[(*offset)++] = name_size;
        !           145:     strcpy(&buf[*offset], name);
        !           146:     *offset += name_size;
        !           147: 
        !           148: error:
        !           149:     return ret;
        !           150: }
        !           151: 
        !           152: static int gen_issuer(const char * dn[], uint8_t *buf, int *offset)
        !           153: {
        !           154:     int ret = X509_OK;
        !           155:     int seq_offset;
        !           156:     int seq_size = pre_adjust_with_size(
        !           157:                             ASN1_SEQUENCE, &seq_offset, buf, offset);
        !           158:     char fqdn[128]; 
        !           159: 
        !           160:     /* we need the common name, so if not configured, work out the fully
        !           161:      * qualified domain name */
        !           162:     if (dn[X509_COMMON_NAME] == NULL || strlen(dn[X509_COMMON_NAME]) == 0)
        !           163:     {
        !           164:         int fqdn_len;
        !           165:         gethostname(fqdn, sizeof(fqdn));
        !           166:         fqdn_len = strlen(fqdn);
        !           167:         fqdn[fqdn_len++] = '.';
        !           168:         getdomainname(&fqdn[fqdn_len], sizeof(fqdn)-fqdn_len);
        !           169:         fqdn_len = strlen(fqdn);
        !           170: 
        !           171:         if (fqdn[fqdn_len-1] == '.')    /* ensure '.' is not last char */
        !           172:             fqdn[fqdn_len-1] = 0;
        !           173: 
        !           174:         dn[X509_COMMON_NAME] = fqdn;
        !           175:     }
        !           176: 
        !           177:     if ((ret = gen_dn(dn[X509_COMMON_NAME], 3, buf, offset)))
        !           178:         goto error;
        !           179: 
        !           180:     if (dn[X509_ORGANIZATION] != NULL && strlen(dn[X509_ORGANIZATION]) > 0)
        !           181:     {
        !           182:         if ((ret = gen_dn(dn[X509_ORGANIZATION], 10, buf, offset)))
        !           183:             goto error;
        !           184:     }
        !           185: 
        !           186:     if (dn[X509_ORGANIZATIONAL_UNIT] != NULL &&
        !           187:                                 strlen(dn[X509_ORGANIZATIONAL_UNIT]) > 0)
        !           188:     {
        !           189:         if ((ret = gen_dn(dn[X509_ORGANIZATIONAL_UNIT], 11, buf, offset)))
        !           190:             goto error;
        !           191:     }
        !           192: 
        !           193:     adjust_with_size(seq_size, seq_offset, buf, offset);
        !           194: 
        !           195: error:
        !           196:     return ret;
        !           197: }
        !           198: 
        !           199: static void gen_utc_time(uint8_t *buf, int *offset)
        !           200: {
        !           201:     static const uint8_t time_seq[] = 
        !           202:     {
        !           203:         ASN1_SEQUENCE, 30, 
        !           204:         ASN1_UTC_TIME, 13, 
        !           205:         '0', '7', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z', 
        !           206:         ASN1_UTC_TIME, 13,  /* make it good for 30 or so years */
        !           207:         '3', '8', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z'
        !           208:     };
        !           209: 
        !           210:     /* fixed time */
        !           211:     memcpy(&buf[*offset], time_seq, sizeof(time_seq));
        !           212:     *offset += sizeof(time_seq);
        !           213: }
        !           214: 
        !           215: static void gen_pub_key2(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
        !           216: {
        !           217:     static const uint8_t pub_key_seq[] = 
        !           218:     {
        !           219:         ASN1_INTEGER, 0x03, 0x01, 0x00, 0x01 /* INTEGER 65537 */
        !           220:     };
        !           221: 
        !           222:     int seq_offset;
        !           223:     int pub_key_size = rsa_ctx->num_octets;
        !           224:     uint8_t *block = (uint8_t *)alloca(pub_key_size);
        !           225:     int seq_size = pre_adjust_with_size(
        !           226:                             ASN1_SEQUENCE, &seq_offset, buf, offset);
        !           227:     buf[(*offset)++] = ASN1_INTEGER;
        !           228:     bi_export(rsa_ctx->bi_ctx, rsa_ctx->m, block, pub_key_size);
        !           229: 
        !           230:     if (*block & 0x80)  /* make integer positive */
        !           231:     {
        !           232:         set_gen_length(pub_key_size+1, buf, offset);
        !           233:         buf[(*offset)++] = 0;
        !           234:     }
        !           235:     else
        !           236:         set_gen_length(pub_key_size, buf, offset);
        !           237: 
        !           238:     memcpy(&buf[*offset], block, pub_key_size);
        !           239:     *offset += pub_key_size;
        !           240:     memcpy(&buf[*offset], pub_key_seq, sizeof(pub_key_seq));
        !           241:     *offset += sizeof(pub_key_seq);
        !           242:     adjust_with_size(seq_size, seq_offset, buf, offset);
        !           243: }
        !           244: 
        !           245: static void gen_pub_key1(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
        !           246: {
        !           247:     int seq_offset;
        !           248:     int seq_size = pre_adjust_with_size(
        !           249:                             ASN1_BIT_STRING, &seq_offset, buf, offset);
        !           250:     buf[(*offset)++] = 0;   /* bit string is multiple of 8 */
        !           251:     gen_pub_key2(rsa_ctx, buf, offset);
        !           252:     adjust_with_size(seq_size, seq_offset, buf, offset);
        !           253: }
        !           254: 
        !           255: static void gen_pub_key(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
        !           256: {
        !           257:     /*  OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */
        !           258:     static const uint8_t rsa_enc_oid[] =
        !           259:     {
        !           260:         ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09,
        !           261:         0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
        !           262:         ASN1_NULL, 0x00
        !           263:     };
        !           264: 
        !           265:     int seq_offset;
        !           266:     int seq_size = pre_adjust_with_size(
        !           267:                             ASN1_SEQUENCE, &seq_offset, buf, offset);
        !           268: 
        !           269:     memcpy(&buf[*offset], rsa_enc_oid, sizeof(rsa_enc_oid));
        !           270:     *offset += sizeof(rsa_enc_oid);
        !           271:     gen_pub_key1(rsa_ctx, buf, offset);
        !           272:     adjust_with_size(seq_size, seq_offset, buf, offset);
        !           273: }
        !           274: 
        !           275: static void gen_signature(const RSA_CTX *rsa_ctx, const uint8_t *sha_dgst, 
        !           276:                         uint8_t *buf, int *offset)
        !           277: {
        !           278:     static const uint8_t asn1_sig[] = 
        !           279:     {
        !           280:         ASN1_SEQUENCE,  0x21, ASN1_SEQUENCE, 0x09, ASN1_OID, 0x05, 
        !           281:         0x2b, 0x0e, 0x03, 0x02, 0x1a, /* sha1 (1 3 14 3 2 26) */
        !           282:         ASN1_NULL, 0x00, ASN1_OCTET_STRING, 0x14 
        !           283:     };
        !           284: 
        !           285:     uint8_t *enc_block = (uint8_t *)alloca(rsa_ctx->num_octets);
        !           286:     uint8_t *block = (uint8_t *)alloca(sizeof(asn1_sig) + SHA1_SIZE);
        !           287:     int sig_size;
        !           288: 
        !           289:     /* add the digest as an embedded asn.1 sequence */
        !           290:     memcpy(block, asn1_sig, sizeof(asn1_sig));
        !           291:     memcpy(&block[sizeof(asn1_sig)], sha_dgst, SHA1_SIZE);
        !           292: 
        !           293:     sig_size = RSA_encrypt(rsa_ctx, block, 
        !           294:                             sizeof(asn1_sig) + SHA1_SIZE, enc_block, 1);
        !           295: 
        !           296:     buf[(*offset)++] = ASN1_BIT_STRING;
        !           297:     set_gen_length(sig_size+1, buf, offset);
        !           298:     buf[(*offset)++] = 0;   /* bit string is multiple of 8 */
        !           299:     memcpy(&buf[*offset], enc_block, sig_size);
        !           300:     *offset += sig_size;
        !           301: }
        !           302: 
        !           303: static int gen_tbs_cert(const char * dn[],
        !           304:                     const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset,
        !           305:                     uint8_t *sha_dgst)
        !           306: {
        !           307:     int ret = X509_OK;
        !           308:     SHA1_CTX sha_ctx;
        !           309:     int seq_offset;
        !           310:     int begin_tbs = *offset;
        !           311:     int seq_size = pre_adjust_with_size(
        !           312:                         ASN1_SEQUENCE, &seq_offset, buf, offset);
        !           313: 
        !           314:     gen_serial_number(buf, offset);
        !           315:     gen_signature_alg(buf, offset);
        !           316: 
        !           317:     /* CA certicate issuer */
        !           318:     if ((ret = gen_issuer(dn, buf, offset)))
        !           319:         goto error;
        !           320: 
        !           321:     gen_utc_time(buf, offset);
        !           322: 
        !           323:     /* certificate issuer */
        !           324:     if ((ret = gen_issuer(dn, buf, offset)))
        !           325:         goto error;
        !           326: 
        !           327:     gen_pub_key(rsa_ctx, buf, offset);
        !           328:     adjust_with_size(seq_size, seq_offset, buf, offset);
        !           329: 
        !           330:     SHA1_Init(&sha_ctx);
        !           331:     SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs);
        !           332:     SHA1_Final(sha_dgst, &sha_ctx);
        !           333: 
        !           334: error:
        !           335:     return ret;
        !           336: }
        !           337: 
        !           338: /**
        !           339:  * Create a new certificate.
        !           340:  */
        !           341: EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data)
        !           342: {
        !           343:     int ret = X509_OK, offset = 0, seq_offset;
        !           344:     /* allocate enough space to load a new certificate */
        !           345:     uint8_t *buf = (uint8_t *)alloca(ssl_ctx->rsa_ctx->num_octets*2 + 512);
        !           346:     uint8_t sha_dgst[SHA1_SIZE];
        !           347:     int seq_size = pre_adjust_with_size(ASN1_SEQUENCE, 
        !           348:                                     &seq_offset, buf, &offset);
        !           349: 
        !           350:     if ((ret = gen_tbs_cert(dn, ssl_ctx->rsa_ctx, buf, &offset, sha_dgst)) < 0)
        !           351:         goto error;
        !           352: 
        !           353:     gen_signature_alg(buf, &offset);
        !           354:     gen_signature(ssl_ctx->rsa_ctx, sha_dgst, buf, &offset);
        !           355:     adjust_with_size(seq_size, seq_offset, buf, &offset);
        !           356:     *cert_data = (uint8_t *)malloc(offset); /* create the exact memory for it */
        !           357:     memcpy(*cert_data, buf, offset);
        !           358: 
        !           359: error:
        !           360:     return ret < 0 ? ret : offset;
        !           361: }
        !           362: 
        !           363: #endif
        !           364: 

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