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>