Rough and ready port of axTLS
ssl/gen_cert.c@0:5a29fd060ac8, 2013-05-13 (annotated)
- Committer:
- ashleymills
- Date:
- Mon May 13 18:15:18 2013 +0000
- Revision:
- 0:5a29fd060ac8
initial commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ashleymills | 0:5a29fd060ac8 | 1 | /* |
ashleymills | 0:5a29fd060ac8 | 2 | * Copyright (c) 2007, Cameron Rich |
ashleymills | 0:5a29fd060ac8 | 3 | * |
ashleymills | 0:5a29fd060ac8 | 4 | * All rights reserved. |
ashleymills | 0:5a29fd060ac8 | 5 | * |
ashleymills | 0:5a29fd060ac8 | 6 | * Redistribution and use in source and binary forms, with or without |
ashleymills | 0:5a29fd060ac8 | 7 | * modification, are permitted provided that the following conditions are met: |
ashleymills | 0:5a29fd060ac8 | 8 | * |
ashleymills | 0:5a29fd060ac8 | 9 | * * Redistributions of source code must retain the above copyright notice, |
ashleymills | 0:5a29fd060ac8 | 10 | * this list of conditions and the following disclaimer. |
ashleymills | 0:5a29fd060ac8 | 11 | * * Redistributions in binary form must reproduce the above copyright notice, |
ashleymills | 0:5a29fd060ac8 | 12 | * this list of conditions and the following disclaimer in the documentation |
ashleymills | 0:5a29fd060ac8 | 13 | * and/or other materials provided with the distribution. |
ashleymills | 0:5a29fd060ac8 | 14 | * * Neither the name of the axTLS project nor the names of its contributors |
ashleymills | 0:5a29fd060ac8 | 15 | * may be used to endorse or promote products derived from this software |
ashleymills | 0:5a29fd060ac8 | 16 | * without specific prior written permission. |
ashleymills | 0:5a29fd060ac8 | 17 | * |
ashleymills | 0:5a29fd060ac8 | 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
ashleymills | 0:5a29fd060ac8 | 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
ashleymills | 0:5a29fd060ac8 | 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
ashleymills | 0:5a29fd060ac8 | 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
ashleymills | 0:5a29fd060ac8 | 22 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
ashleymills | 0:5a29fd060ac8 | 23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
ashleymills | 0:5a29fd060ac8 | 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
ashleymills | 0:5a29fd060ac8 | 25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
ashleymills | 0:5a29fd060ac8 | 26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
ashleymills | 0:5a29fd060ac8 | 27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
ashleymills | 0:5a29fd060ac8 | 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
ashleymills | 0:5a29fd060ac8 | 29 | */ |
ashleymills | 0:5a29fd060ac8 | 30 | |
ashleymills | 0:5a29fd060ac8 | 31 | #include "config.h" |
ashleymills | 0:5a29fd060ac8 | 32 | |
ashleymills | 0:5a29fd060ac8 | 33 | #ifdef CONFIG_SSL_GENERATE_X509_CERT |
ashleymills | 0:5a29fd060ac8 | 34 | #include <string.h> |
ashleymills | 0:5a29fd060ac8 | 35 | #include <stdlib.h> |
ashleymills | 0:5a29fd060ac8 | 36 | #include "os_port.h" |
ashleymills | 0:5a29fd060ac8 | 37 | #include "ssl.h" |
ashleymills | 0:5a29fd060ac8 | 38 | |
ashleymills | 0:5a29fd060ac8 | 39 | /** |
ashleymills | 0:5a29fd060ac8 | 40 | * Generate a basic X.509 certificate |
ashleymills | 0:5a29fd060ac8 | 41 | */ |
ashleymills | 0:5a29fd060ac8 | 42 | |
ashleymills | 0:5a29fd060ac8 | 43 | static uint8_t set_gen_length(int len, uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 44 | { |
ashleymills | 0:5a29fd060ac8 | 45 | if (len < 0x80) /* short form */ |
ashleymills | 0:5a29fd060ac8 | 46 | { |
ashleymills | 0:5a29fd060ac8 | 47 | buf[(*offset)++] = len; |
ashleymills | 0:5a29fd060ac8 | 48 | return 1; |
ashleymills | 0:5a29fd060ac8 | 49 | } |
ashleymills | 0:5a29fd060ac8 | 50 | else /* long form */ |
ashleymills | 0:5a29fd060ac8 | 51 | { |
ashleymills | 0:5a29fd060ac8 | 52 | int i, length_bytes = 0; |
ashleymills | 0:5a29fd060ac8 | 53 | |
ashleymills | 0:5a29fd060ac8 | 54 | if (len & 0x00FF0000) |
ashleymills | 0:5a29fd060ac8 | 55 | length_bytes = 3; |
ashleymills | 0:5a29fd060ac8 | 56 | else if (len & 0x0000FF00) |
ashleymills | 0:5a29fd060ac8 | 57 | length_bytes = 2; |
ashleymills | 0:5a29fd060ac8 | 58 | else if (len & 0x000000FF) |
ashleymills | 0:5a29fd060ac8 | 59 | length_bytes = 1; |
ashleymills | 0:5a29fd060ac8 | 60 | |
ashleymills | 0:5a29fd060ac8 | 61 | buf[(*offset)++] = 0x80 + length_bytes; |
ashleymills | 0:5a29fd060ac8 | 62 | |
ashleymills | 0:5a29fd060ac8 | 63 | for (i = length_bytes-1; i >= 0; i--) |
ashleymills | 0:5a29fd060ac8 | 64 | { |
ashleymills | 0:5a29fd060ac8 | 65 | buf[*offset+i] = len & 0xFF; |
ashleymills | 0:5a29fd060ac8 | 66 | len >>= 8; |
ashleymills | 0:5a29fd060ac8 | 67 | } |
ashleymills | 0:5a29fd060ac8 | 68 | |
ashleymills | 0:5a29fd060ac8 | 69 | *offset += length_bytes; |
ashleymills | 0:5a29fd060ac8 | 70 | return length_bytes+1; |
ashleymills | 0:5a29fd060ac8 | 71 | } |
ashleymills | 0:5a29fd060ac8 | 72 | } |
ashleymills | 0:5a29fd060ac8 | 73 | |
ashleymills | 0:5a29fd060ac8 | 74 | static int pre_adjust_with_size(uint8_t type, |
ashleymills | 0:5a29fd060ac8 | 75 | int *seq_offset, uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 76 | { |
ashleymills | 0:5a29fd060ac8 | 77 | buf[(*offset)++] = type; |
ashleymills | 0:5a29fd060ac8 | 78 | *seq_offset = *offset; |
ashleymills | 0:5a29fd060ac8 | 79 | *offset += 4; /* fill in later */ |
ashleymills | 0:5a29fd060ac8 | 80 | return *offset; |
ashleymills | 0:5a29fd060ac8 | 81 | } |
ashleymills | 0:5a29fd060ac8 | 82 | |
ashleymills | 0:5a29fd060ac8 | 83 | static void adjust_with_size(int seq_size, int seq_start, |
ashleymills | 0:5a29fd060ac8 | 84 | uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 85 | { |
ashleymills | 0:5a29fd060ac8 | 86 | uint8_t seq_byte_size; |
ashleymills | 0:5a29fd060ac8 | 87 | int orig_seq_size = seq_size; |
ashleymills | 0:5a29fd060ac8 | 88 | int orig_seq_start = seq_start; |
ashleymills | 0:5a29fd060ac8 | 89 | |
ashleymills | 0:5a29fd060ac8 | 90 | seq_size = *offset-seq_size; |
ashleymills | 0:5a29fd060ac8 | 91 | seq_byte_size = set_gen_length(seq_size, buf, &seq_start); |
ashleymills | 0:5a29fd060ac8 | 92 | |
ashleymills | 0:5a29fd060ac8 | 93 | if (seq_byte_size != 4) |
ashleymills | 0:5a29fd060ac8 | 94 | { |
ashleymills | 0:5a29fd060ac8 | 95 | memmove(&buf[orig_seq_start+seq_byte_size], |
ashleymills | 0:5a29fd060ac8 | 96 | &buf[orig_seq_size], seq_size); |
ashleymills | 0:5a29fd060ac8 | 97 | *offset -= 4-seq_byte_size; |
ashleymills | 0:5a29fd060ac8 | 98 | } |
ashleymills | 0:5a29fd060ac8 | 99 | } |
ashleymills | 0:5a29fd060ac8 | 100 | |
ashleymills | 0:5a29fd060ac8 | 101 | static void gen_serial_number(uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 102 | { |
ashleymills | 0:5a29fd060ac8 | 103 | static const uint8_t ser_oid[] = { ASN1_INTEGER, 1, 0x7F }; |
ashleymills | 0:5a29fd060ac8 | 104 | memcpy(&buf[*offset], ser_oid , sizeof(ser_oid)); |
ashleymills | 0:5a29fd060ac8 | 105 | *offset += sizeof(ser_oid); |
ashleymills | 0:5a29fd060ac8 | 106 | } |
ashleymills | 0:5a29fd060ac8 | 107 | |
ashleymills | 0:5a29fd060ac8 | 108 | static void gen_signature_alg(uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 109 | { |
ashleymills | 0:5a29fd060ac8 | 110 | /* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */ |
ashleymills | 0:5a29fd060ac8 | 111 | static const uint8_t sig_oid[] = |
ashleymills | 0:5a29fd060ac8 | 112 | { |
ashleymills | 0:5a29fd060ac8 | 113 | ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09, |
ashleymills | 0:5a29fd060ac8 | 114 | 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, |
ashleymills | 0:5a29fd060ac8 | 115 | ASN1_NULL, 0x00 |
ashleymills | 0:5a29fd060ac8 | 116 | }; |
ashleymills | 0:5a29fd060ac8 | 117 | |
ashleymills | 0:5a29fd060ac8 | 118 | memcpy(&buf[*offset], sig_oid, sizeof(sig_oid)); |
ashleymills | 0:5a29fd060ac8 | 119 | *offset += sizeof(sig_oid); |
ashleymills | 0:5a29fd060ac8 | 120 | } |
ashleymills | 0:5a29fd060ac8 | 121 | |
ashleymills | 0:5a29fd060ac8 | 122 | static int gen_dn(const char *name, uint8_t dn_type, |
ashleymills | 0:5a29fd060ac8 | 123 | uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 124 | { |
ashleymills | 0:5a29fd060ac8 | 125 | int ret = X509_OK; |
ashleymills | 0:5a29fd060ac8 | 126 | int name_size = strlen(name); |
ashleymills | 0:5a29fd060ac8 | 127 | |
ashleymills | 0:5a29fd060ac8 | 128 | if (name_size > 0x70) /* just too big */ |
ashleymills | 0:5a29fd060ac8 | 129 | { |
ashleymills | 0:5a29fd060ac8 | 130 | ret = X509_NOT_OK; |
ashleymills | 0:5a29fd060ac8 | 131 | goto error; |
ashleymills | 0:5a29fd060ac8 | 132 | } |
ashleymills | 0:5a29fd060ac8 | 133 | |
ashleymills | 0:5a29fd060ac8 | 134 | buf[(*offset)++] = ASN1_SET; |
ashleymills | 0:5a29fd060ac8 | 135 | set_gen_length(9+name_size, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 136 | buf[(*offset)++] = ASN1_SEQUENCE; |
ashleymills | 0:5a29fd060ac8 | 137 | set_gen_length(7+name_size, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 138 | buf[(*offset)++] = ASN1_OID; |
ashleymills | 0:5a29fd060ac8 | 139 | buf[(*offset)++] = 3; |
ashleymills | 0:5a29fd060ac8 | 140 | buf[(*offset)++] = 0x55; |
ashleymills | 0:5a29fd060ac8 | 141 | buf[(*offset)++] = 0x04; |
ashleymills | 0:5a29fd060ac8 | 142 | buf[(*offset)++] = dn_type; |
ashleymills | 0:5a29fd060ac8 | 143 | buf[(*offset)++] = ASN1_PRINTABLE_STR; |
ashleymills | 0:5a29fd060ac8 | 144 | buf[(*offset)++] = name_size; |
ashleymills | 0:5a29fd060ac8 | 145 | strcpy(&buf[*offset], name); |
ashleymills | 0:5a29fd060ac8 | 146 | *offset += name_size; |
ashleymills | 0:5a29fd060ac8 | 147 | |
ashleymills | 0:5a29fd060ac8 | 148 | error: |
ashleymills | 0:5a29fd060ac8 | 149 | return ret; |
ashleymills | 0:5a29fd060ac8 | 150 | } |
ashleymills | 0:5a29fd060ac8 | 151 | |
ashleymills | 0:5a29fd060ac8 | 152 | static int gen_issuer(const char * dn[], uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 153 | { |
ashleymills | 0:5a29fd060ac8 | 154 | int ret = X509_OK; |
ashleymills | 0:5a29fd060ac8 | 155 | int seq_offset; |
ashleymills | 0:5a29fd060ac8 | 156 | int seq_size = pre_adjust_with_size( |
ashleymills | 0:5a29fd060ac8 | 157 | ASN1_SEQUENCE, &seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 158 | char fqdn[128]; |
ashleymills | 0:5a29fd060ac8 | 159 | |
ashleymills | 0:5a29fd060ac8 | 160 | /* we need the common name, so if not configured, work out the fully |
ashleymills | 0:5a29fd060ac8 | 161 | * qualified domain name */ |
ashleymills | 0:5a29fd060ac8 | 162 | if (dn[X509_COMMON_NAME] == NULL || strlen(dn[X509_COMMON_NAME]) == 0) |
ashleymills | 0:5a29fd060ac8 | 163 | { |
ashleymills | 0:5a29fd060ac8 | 164 | int fqdn_len; |
ashleymills | 0:5a29fd060ac8 | 165 | gethostname(fqdn, sizeof(fqdn)); |
ashleymills | 0:5a29fd060ac8 | 166 | fqdn_len = strlen(fqdn); |
ashleymills | 0:5a29fd060ac8 | 167 | fqdn[fqdn_len++] = '.'; |
ashleymills | 0:5a29fd060ac8 | 168 | getdomainname(&fqdn[fqdn_len], sizeof(fqdn)-fqdn_len); |
ashleymills | 0:5a29fd060ac8 | 169 | fqdn_len = strlen(fqdn); |
ashleymills | 0:5a29fd060ac8 | 170 | |
ashleymills | 0:5a29fd060ac8 | 171 | if (fqdn[fqdn_len-1] == '.') /* ensure '.' is not last char */ |
ashleymills | 0:5a29fd060ac8 | 172 | fqdn[fqdn_len-1] = 0; |
ashleymills | 0:5a29fd060ac8 | 173 | |
ashleymills | 0:5a29fd060ac8 | 174 | dn[X509_COMMON_NAME] = fqdn; |
ashleymills | 0:5a29fd060ac8 | 175 | } |
ashleymills | 0:5a29fd060ac8 | 176 | |
ashleymills | 0:5a29fd060ac8 | 177 | if ((ret = gen_dn(dn[X509_COMMON_NAME], 3, buf, offset))) |
ashleymills | 0:5a29fd060ac8 | 178 | goto error; |
ashleymills | 0:5a29fd060ac8 | 179 | |
ashleymills | 0:5a29fd060ac8 | 180 | if (dn[X509_ORGANIZATION] != NULL && strlen(dn[X509_ORGANIZATION]) > 0) |
ashleymills | 0:5a29fd060ac8 | 181 | { |
ashleymills | 0:5a29fd060ac8 | 182 | if ((ret = gen_dn(dn[X509_ORGANIZATION], 10, buf, offset))) |
ashleymills | 0:5a29fd060ac8 | 183 | goto error; |
ashleymills | 0:5a29fd060ac8 | 184 | } |
ashleymills | 0:5a29fd060ac8 | 185 | |
ashleymills | 0:5a29fd060ac8 | 186 | if (dn[X509_ORGANIZATIONAL_UNIT] != NULL && |
ashleymills | 0:5a29fd060ac8 | 187 | strlen(dn[X509_ORGANIZATIONAL_UNIT]) > 0) |
ashleymills | 0:5a29fd060ac8 | 188 | { |
ashleymills | 0:5a29fd060ac8 | 189 | if ((ret = gen_dn(dn[X509_ORGANIZATIONAL_UNIT], 11, buf, offset))) |
ashleymills | 0:5a29fd060ac8 | 190 | goto error; |
ashleymills | 0:5a29fd060ac8 | 191 | } |
ashleymills | 0:5a29fd060ac8 | 192 | |
ashleymills | 0:5a29fd060ac8 | 193 | adjust_with_size(seq_size, seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 194 | |
ashleymills | 0:5a29fd060ac8 | 195 | error: |
ashleymills | 0:5a29fd060ac8 | 196 | return ret; |
ashleymills | 0:5a29fd060ac8 | 197 | } |
ashleymills | 0:5a29fd060ac8 | 198 | |
ashleymills | 0:5a29fd060ac8 | 199 | static void gen_utc_time(uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 200 | { |
ashleymills | 0:5a29fd060ac8 | 201 | static const uint8_t time_seq[] = |
ashleymills | 0:5a29fd060ac8 | 202 | { |
ashleymills | 0:5a29fd060ac8 | 203 | ASN1_SEQUENCE, 30, |
ashleymills | 0:5a29fd060ac8 | 204 | ASN1_UTC_TIME, 13, |
ashleymills | 0:5a29fd060ac8 | 205 | '0', '7', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z', |
ashleymills | 0:5a29fd060ac8 | 206 | ASN1_UTC_TIME, 13, /* make it good for 30 or so years */ |
ashleymills | 0:5a29fd060ac8 | 207 | '3', '8', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z' |
ashleymills | 0:5a29fd060ac8 | 208 | }; |
ashleymills | 0:5a29fd060ac8 | 209 | |
ashleymills | 0:5a29fd060ac8 | 210 | /* fixed time */ |
ashleymills | 0:5a29fd060ac8 | 211 | memcpy(&buf[*offset], time_seq, sizeof(time_seq)); |
ashleymills | 0:5a29fd060ac8 | 212 | *offset += sizeof(time_seq); |
ashleymills | 0:5a29fd060ac8 | 213 | } |
ashleymills | 0:5a29fd060ac8 | 214 | |
ashleymills | 0:5a29fd060ac8 | 215 | static void gen_pub_key2(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 216 | { |
ashleymills | 0:5a29fd060ac8 | 217 | static const uint8_t pub_key_seq[] = |
ashleymills | 0:5a29fd060ac8 | 218 | { |
ashleymills | 0:5a29fd060ac8 | 219 | ASN1_INTEGER, 0x03, 0x01, 0x00, 0x01 /* INTEGER 65537 */ |
ashleymills | 0:5a29fd060ac8 | 220 | }; |
ashleymills | 0:5a29fd060ac8 | 221 | |
ashleymills | 0:5a29fd060ac8 | 222 | int seq_offset; |
ashleymills | 0:5a29fd060ac8 | 223 | int pub_key_size = rsa_ctx->num_octets; |
ashleymills | 0:5a29fd060ac8 | 224 | uint8_t *block = (uint8_t *)alloca(pub_key_size); |
ashleymills | 0:5a29fd060ac8 | 225 | int seq_size = pre_adjust_with_size( |
ashleymills | 0:5a29fd060ac8 | 226 | ASN1_SEQUENCE, &seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 227 | buf[(*offset)++] = ASN1_INTEGER; |
ashleymills | 0:5a29fd060ac8 | 228 | bi_export(rsa_ctx->bi_ctx, rsa_ctx->m, block, pub_key_size); |
ashleymills | 0:5a29fd060ac8 | 229 | |
ashleymills | 0:5a29fd060ac8 | 230 | if (*block & 0x80) /* make integer positive */ |
ashleymills | 0:5a29fd060ac8 | 231 | { |
ashleymills | 0:5a29fd060ac8 | 232 | set_gen_length(pub_key_size+1, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 233 | buf[(*offset)++] = 0; |
ashleymills | 0:5a29fd060ac8 | 234 | } |
ashleymills | 0:5a29fd060ac8 | 235 | else |
ashleymills | 0:5a29fd060ac8 | 236 | set_gen_length(pub_key_size, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 237 | |
ashleymills | 0:5a29fd060ac8 | 238 | memcpy(&buf[*offset], block, pub_key_size); |
ashleymills | 0:5a29fd060ac8 | 239 | *offset += pub_key_size; |
ashleymills | 0:5a29fd060ac8 | 240 | memcpy(&buf[*offset], pub_key_seq, sizeof(pub_key_seq)); |
ashleymills | 0:5a29fd060ac8 | 241 | *offset += sizeof(pub_key_seq); |
ashleymills | 0:5a29fd060ac8 | 242 | adjust_with_size(seq_size, seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 243 | } |
ashleymills | 0:5a29fd060ac8 | 244 | |
ashleymills | 0:5a29fd060ac8 | 245 | static void gen_pub_key1(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 246 | { |
ashleymills | 0:5a29fd060ac8 | 247 | int seq_offset; |
ashleymills | 0:5a29fd060ac8 | 248 | int seq_size = pre_adjust_with_size( |
ashleymills | 0:5a29fd060ac8 | 249 | ASN1_BIT_STRING, &seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 250 | buf[(*offset)++] = 0; /* bit string is multiple of 8 */ |
ashleymills | 0:5a29fd060ac8 | 251 | gen_pub_key2(rsa_ctx, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 252 | adjust_with_size(seq_size, seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 253 | } |
ashleymills | 0:5a29fd060ac8 | 254 | |
ashleymills | 0:5a29fd060ac8 | 255 | static void gen_pub_key(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 256 | { |
ashleymills | 0:5a29fd060ac8 | 257 | /* OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */ |
ashleymills | 0:5a29fd060ac8 | 258 | static const uint8_t rsa_enc_oid[] = |
ashleymills | 0:5a29fd060ac8 | 259 | { |
ashleymills | 0:5a29fd060ac8 | 260 | ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09, |
ashleymills | 0:5a29fd060ac8 | 261 | 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, |
ashleymills | 0:5a29fd060ac8 | 262 | ASN1_NULL, 0x00 |
ashleymills | 0:5a29fd060ac8 | 263 | }; |
ashleymills | 0:5a29fd060ac8 | 264 | |
ashleymills | 0:5a29fd060ac8 | 265 | int seq_offset; |
ashleymills | 0:5a29fd060ac8 | 266 | int seq_size = pre_adjust_with_size( |
ashleymills | 0:5a29fd060ac8 | 267 | ASN1_SEQUENCE, &seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 268 | |
ashleymills | 0:5a29fd060ac8 | 269 | memcpy(&buf[*offset], rsa_enc_oid, sizeof(rsa_enc_oid)); |
ashleymills | 0:5a29fd060ac8 | 270 | *offset += sizeof(rsa_enc_oid); |
ashleymills | 0:5a29fd060ac8 | 271 | gen_pub_key1(rsa_ctx, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 272 | adjust_with_size(seq_size, seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 273 | } |
ashleymills | 0:5a29fd060ac8 | 274 | |
ashleymills | 0:5a29fd060ac8 | 275 | static void gen_signature(const RSA_CTX *rsa_ctx, const uint8_t *sha_dgst, |
ashleymills | 0:5a29fd060ac8 | 276 | uint8_t *buf, int *offset) |
ashleymills | 0:5a29fd060ac8 | 277 | { |
ashleymills | 0:5a29fd060ac8 | 278 | static const uint8_t asn1_sig[] = |
ashleymills | 0:5a29fd060ac8 | 279 | { |
ashleymills | 0:5a29fd060ac8 | 280 | ASN1_SEQUENCE, 0x21, ASN1_SEQUENCE, 0x09, ASN1_OID, 0x05, |
ashleymills | 0:5a29fd060ac8 | 281 | 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* sha1 (1 3 14 3 2 26) */ |
ashleymills | 0:5a29fd060ac8 | 282 | ASN1_NULL, 0x00, ASN1_OCTET_STRING, 0x14 |
ashleymills | 0:5a29fd060ac8 | 283 | }; |
ashleymills | 0:5a29fd060ac8 | 284 | |
ashleymills | 0:5a29fd060ac8 | 285 | uint8_t *enc_block = (uint8_t *)alloca(rsa_ctx->num_octets); |
ashleymills | 0:5a29fd060ac8 | 286 | uint8_t *block = (uint8_t *)alloca(sizeof(asn1_sig) + SHA1_SIZE); |
ashleymills | 0:5a29fd060ac8 | 287 | int sig_size; |
ashleymills | 0:5a29fd060ac8 | 288 | |
ashleymills | 0:5a29fd060ac8 | 289 | /* add the digest as an embedded asn.1 sequence */ |
ashleymills | 0:5a29fd060ac8 | 290 | memcpy(block, asn1_sig, sizeof(asn1_sig)); |
ashleymills | 0:5a29fd060ac8 | 291 | memcpy(&block[sizeof(asn1_sig)], sha_dgst, SHA1_SIZE); |
ashleymills | 0:5a29fd060ac8 | 292 | |
ashleymills | 0:5a29fd060ac8 | 293 | sig_size = RSA_encrypt(rsa_ctx, block, |
ashleymills | 0:5a29fd060ac8 | 294 | sizeof(asn1_sig) + SHA1_SIZE, enc_block, 1); |
ashleymills | 0:5a29fd060ac8 | 295 | |
ashleymills | 0:5a29fd060ac8 | 296 | buf[(*offset)++] = ASN1_BIT_STRING; |
ashleymills | 0:5a29fd060ac8 | 297 | set_gen_length(sig_size+1, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 298 | buf[(*offset)++] = 0; /* bit string is multiple of 8 */ |
ashleymills | 0:5a29fd060ac8 | 299 | memcpy(&buf[*offset], enc_block, sig_size); |
ashleymills | 0:5a29fd060ac8 | 300 | *offset += sig_size; |
ashleymills | 0:5a29fd060ac8 | 301 | } |
ashleymills | 0:5a29fd060ac8 | 302 | |
ashleymills | 0:5a29fd060ac8 | 303 | static int gen_tbs_cert(const char * dn[], |
ashleymills | 0:5a29fd060ac8 | 304 | const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset, |
ashleymills | 0:5a29fd060ac8 | 305 | uint8_t *sha_dgst) |
ashleymills | 0:5a29fd060ac8 | 306 | { |
ashleymills | 0:5a29fd060ac8 | 307 | int ret = X509_OK; |
ashleymills | 0:5a29fd060ac8 | 308 | SHA1_CTX sha_ctx; |
ashleymills | 0:5a29fd060ac8 | 309 | int seq_offset; |
ashleymills | 0:5a29fd060ac8 | 310 | int begin_tbs = *offset; |
ashleymills | 0:5a29fd060ac8 | 311 | int seq_size = pre_adjust_with_size( |
ashleymills | 0:5a29fd060ac8 | 312 | ASN1_SEQUENCE, &seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 313 | |
ashleymills | 0:5a29fd060ac8 | 314 | gen_serial_number(buf, offset); |
ashleymills | 0:5a29fd060ac8 | 315 | gen_signature_alg(buf, offset); |
ashleymills | 0:5a29fd060ac8 | 316 | |
ashleymills | 0:5a29fd060ac8 | 317 | /* CA certicate issuer */ |
ashleymills | 0:5a29fd060ac8 | 318 | if ((ret = gen_issuer(dn, buf, offset))) |
ashleymills | 0:5a29fd060ac8 | 319 | goto error; |
ashleymills | 0:5a29fd060ac8 | 320 | |
ashleymills | 0:5a29fd060ac8 | 321 | gen_utc_time(buf, offset); |
ashleymills | 0:5a29fd060ac8 | 322 | |
ashleymills | 0:5a29fd060ac8 | 323 | /* certificate issuer */ |
ashleymills | 0:5a29fd060ac8 | 324 | if ((ret = gen_issuer(dn, buf, offset))) |
ashleymills | 0:5a29fd060ac8 | 325 | goto error; |
ashleymills | 0:5a29fd060ac8 | 326 | |
ashleymills | 0:5a29fd060ac8 | 327 | gen_pub_key(rsa_ctx, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 328 | adjust_with_size(seq_size, seq_offset, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 329 | |
ashleymills | 0:5a29fd060ac8 | 330 | SHA1_Init(&sha_ctx); |
ashleymills | 0:5a29fd060ac8 | 331 | SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs); |
ashleymills | 0:5a29fd060ac8 | 332 | SHA1_Final(sha_dgst, &sha_ctx); |
ashleymills | 0:5a29fd060ac8 | 333 | |
ashleymills | 0:5a29fd060ac8 | 334 | error: |
ashleymills | 0:5a29fd060ac8 | 335 | return ret; |
ashleymills | 0:5a29fd060ac8 | 336 | } |
ashleymills | 0:5a29fd060ac8 | 337 | |
ashleymills | 0:5a29fd060ac8 | 338 | /** |
ashleymills | 0:5a29fd060ac8 | 339 | * Create a new certificate. |
ashleymills | 0:5a29fd060ac8 | 340 | */ |
ashleymills | 0:5a29fd060ac8 | 341 | EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data) |
ashleymills | 0:5a29fd060ac8 | 342 | { |
ashleymills | 0:5a29fd060ac8 | 343 | int ret = X509_OK, offset = 0, seq_offset; |
ashleymills | 0:5a29fd060ac8 | 344 | /* allocate enough space to load a new certificate */ |
ashleymills | 0:5a29fd060ac8 | 345 | uint8_t *buf = (uint8_t *)alloca(ssl_ctx->rsa_ctx->num_octets*2 + 512); |
ashleymills | 0:5a29fd060ac8 | 346 | uint8_t sha_dgst[SHA1_SIZE]; |
ashleymills | 0:5a29fd060ac8 | 347 | int seq_size = pre_adjust_with_size(ASN1_SEQUENCE, |
ashleymills | 0:5a29fd060ac8 | 348 | &seq_offset, buf, &offset); |
ashleymills | 0:5a29fd060ac8 | 349 | |
ashleymills | 0:5a29fd060ac8 | 350 | if ((ret = gen_tbs_cert(dn, ssl_ctx->rsa_ctx, buf, &offset, sha_dgst)) < 0) |
ashleymills | 0:5a29fd060ac8 | 351 | goto error; |
ashleymills | 0:5a29fd060ac8 | 352 | |
ashleymills | 0:5a29fd060ac8 | 353 | gen_signature_alg(buf, &offset); |
ashleymills | 0:5a29fd060ac8 | 354 | gen_signature(ssl_ctx->rsa_ctx, sha_dgst, buf, &offset); |
ashleymills | 0:5a29fd060ac8 | 355 | adjust_with_size(seq_size, seq_offset, buf, &offset); |
ashleymills | 0:5a29fd060ac8 | 356 | *cert_data = (uint8_t *)malloc(offset); /* create the exact memory for it */ |
ashleymills | 0:5a29fd060ac8 | 357 | memcpy(*cert_data, buf, offset); |
ashleymills | 0:5a29fd060ac8 | 358 | |
ashleymills | 0:5a29fd060ac8 | 359 | error: |
ashleymills | 0:5a29fd060ac8 | 360 | return ret < 0 ? ret : offset; |
ashleymills | 0:5a29fd060ac8 | 361 | } |
ashleymills | 0:5a29fd060ac8 | 362 | |
ashleymills | 0:5a29fd060ac8 | 363 | #endif |
ashleymills | 0:5a29fd060ac8 | 364 |