1\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 2\ 3\ Permission is hereby granted, free of charge, to any person obtaining 4\ a copy of this software and associated documentation files (the 5\ "Software"), to deal in the Software without restriction, including 6\ without limitation the rights to use, copy, modify, merge, publish, 7\ distribute, sublicense, and/or sell copies of the Software, and to 8\ permit persons to whom the Software is furnished to do so, subject to 9\ the following conditions: 10\ 11\ The above copyright notice and this permission notice shall be 12\ included in all copies or substantial portions of the Software. 13\ 14\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21\ SOFTWARE. 22 23preamble { 24 25#include "inner.h" 26 27#define CTX ((br_x509_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu))) 28#define CONTEXT_NAME br_x509_decoder_context 29 30/* see bearssl_x509.h */ 31void 32br_x509_decoder_init(br_x509_decoder_context *ctx, 33 void (*append_dn)(void *ctx, const void *buf, size_t len), 34 void *append_dn_ctx) 35{ 36 memset(ctx, 0, sizeof *ctx); 37 /* obsolete 38 ctx->err = 0; 39 ctx->hbuf = NULL; 40 ctx->hlen = 0; 41 */ 42 ctx->append_dn = append_dn; 43 ctx->append_dn_ctx = append_dn_ctx; 44 ctx->cpu.dp = &ctx->dp_stack[0]; 45 ctx->cpu.rp = &ctx->rp_stack[0]; 46 br_x509_decoder_init_main(&ctx->cpu); 47 br_x509_decoder_run(&ctx->cpu); 48} 49 50/* see bearssl_x509.h */ 51void 52br_x509_decoder_push(br_x509_decoder_context *ctx, 53 const void *data, size_t len) 54{ 55 ctx->hbuf = data; 56 ctx->hlen = len; 57 br_x509_decoder_run(&ctx->cpu); 58} 59 60} 61 62addr: decoded 63addr: notbefore_days 64addr: notbefore_seconds 65addr: notafter_days 66addr: notafter_seconds 67addr: isCA 68addr: copy_dn 69addr: signer_key_type 70addr: signer_hash_id 71 72cc: read8-low ( -- x ) { 73 if (CTX->hlen == 0) { 74 T0_PUSHi(-1); 75 } else { 76 unsigned char x = *CTX->hbuf ++; 77 if (CTX->copy_dn && CTX->append_dn) { 78 CTX->append_dn(CTX->append_dn_ctx, &x, 1); 79 } 80 CTX->hlen --; 81 T0_PUSH(x); 82 } 83} 84 85cc: read-blob-inner ( addr len -- addr len ) { 86 uint32_t len = T0_POP(); 87 uint32_t addr = T0_POP(); 88 size_t clen = CTX->hlen; 89 if (clen > len) { 90 clen = (size_t)len; 91 } 92 if (addr != 0) { 93 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); 94 } 95 if (CTX->copy_dn && CTX->append_dn) { 96 CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen); 97 } 98 CTX->hbuf += clen; 99 CTX->hlen -= clen; 100 T0_PUSH(addr + clen); 101 T0_PUSH(len - clen); 102} 103 104\ Get the address and length for the pkey_data buffer. 105: addr-len-pkey_data ( -- addr len ) 106 CX 0 8191 { offsetof(br_x509_decoder_context, pkey_data) } 107 CX 0 8191 { BR_X509_BUFSIZE_KEY } ; 108 109\ Copy the public key (RSA) to the permanent buffer. 110cc: copy-rsa-pkey ( nlen elen -- ) { 111 size_t elen = T0_POP(); 112 size_t nlen = T0_POP(); 113 CTX->pkey.key_type = BR_KEYTYPE_RSA; 114 CTX->pkey.key.rsa.n = CTX->pkey_data; 115 CTX->pkey.key.rsa.nlen = nlen; 116 CTX->pkey.key.rsa.e = CTX->pkey_data + nlen; 117 CTX->pkey.key.rsa.elen = elen; 118} 119 120\ Copy the public key (EC) to the permanent buffer. 121cc: copy-ec-pkey ( curve qlen -- ) { 122 size_t qlen = T0_POP(); 123 uint32_t curve = T0_POP(); 124 CTX->pkey.key_type = BR_KEYTYPE_EC; 125 CTX->pkey.key.ec.curve = curve; 126 CTX->pkey.key.ec.q = CTX->pkey_data; 127 CTX->pkey.key.ec.qlen = qlen; 128} 129 130\ Extensions with specific processing. 131OID: basicConstraints 2.5.29.19 132 133\ Process a Basic Constraints extension. We want the "CA" flag only. 134: process-basicConstraints ( lim -- lim ) 135 read-sequence-open 136 read-tag-or-end dup 0x01 = if 137 read-boolean 1 and addr-isCA set8 138 else 139 2drop 140 then 141 skip-close-elt 142 ; 143 144\ Decode a certificate. 145: main ( -- ! ) 146 147 \ Initialise state flags. 148 0 addr-decoded set8 149 0 addr-copy_dn set8 150 151 \ An arbitrary limit for the total certificate size. 152 0xFFFFFF 153 154 \ Open the outer SEQUENCE. 155 read-sequence-open 156 157 \ TBS 158 read-sequence-open 159 160 \ First element may be an explicit version. We accept only 161 \ versions 0 to 2 (certificates v1 to v3). 162 read-tag dup 0x20 = if 163 drop check-constructed read-length-open-elt 164 read-tag 165 0x02 check-tag-primitive 166 read-small-int-value 167 2 > if ERR_X509_UNSUPPORTED fail then 168 close-elt 169 read-tag 170 then 171 172 \ Serial number. We just check that the tag is correct. 173 0x02 check-tag-primitive read-length-skip 174 175 \ Signature algorithm. 176 read-sequence-open skip-close-elt 177 178 \ Issuer name. 179 read-sequence-open skip-close-elt 180 181 \ Validity dates. 182 read-sequence-open 183 read-date addr-notbefore_seconds set32 addr-notbefore_days set32 184 read-date addr-notafter_seconds set32 addr-notafter_days set32 185 close-elt 186 187 \ Subject name. 188 1 addr-copy_dn set8 189 read-sequence-open skip-close-elt 190 0 addr-copy_dn set8 191 192 \ Public Key. 193 read-sequence-open 194 \ Algorithm Identifier. Right now we are only interested in the 195 \ OID, since we only support RSA keys. 196 \ TODO: support EC keys 197 read-sequence-open 198 read-OID ifnot ERR_X509_UNSUPPORTED fail then 199 choice 200 \ RSA public key. 201 rsaEncryption eqOID uf 202 skip-close-elt 203 \ Public key itself: the BIT STRING contains bytes 204 \ (no partial byte) and these bytes encode the 205 \ actual value. 206 read-bits-open 207 \ RSA public key is a SEQUENCE of two 208 \ INTEGER. We get both INTEGER values into 209 \ the pkey_data[] buffer, if they fit. 210 read-sequence-open 211 addr-len-pkey_data 212 read-integer { nlen } 213 addr-len-pkey_data swap nlen + swap nlen - 214 read-integer { elen } 215 close-elt 216 close-elt 217 nlen elen copy-rsa-pkey 218 enduf 219 220 \ EC public key. 221 id-ecPublicKey eqOID uf 222 \ We support only named curves, for which the 223 \ "parameters" field in the AlgorithmIdentifier 224 \ field should be an OID. 225 read-curve-ID { curve } 226 close-elt 227 read-bits-open 228 dup { qlen } 229 dup addr-len-pkey_data rot < if 230 ERR_X509_LIMIT_EXCEEDED fail 231 then 232 read-blob 233 curve qlen copy-ec-pkey 234 enduf 235 ERR_X509_UNSUPPORTED fail 236 endchoice 237 close-elt 238 239 \ This flag will be set to true if the Basic Constraints extension 240 \ is encountered. 241 0 addr-isCA set8 242 243 \ Skip issuerUniqueID and subjectUniqueID, and process extensions 244 \ if present. Extensions are an explicit context tag of value 3 245 \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE 246 \ with an OID, an optional boolean, and a value; the value is 247 \ an OCTET STRING. 248 read-tag-or-end 249 0x21 iftag-skip 250 0x22 iftag-skip 251 dup 0x23 = if 252 drop 253 check-constructed read-length-open-elt 254 read-sequence-open 255 begin dup while 256 read-sequence-open 257 read-OID drop 258 read-tag dup 0x01 = if 259 read-boolean drop 260 read-tag 261 then 262 0x04 check-tag-primitive read-length-open-elt 263 choice 264 \ Extensions with specific processing. 265 basicConstraints eqOID uf 266 process-basicConstraints 267 enduf 268 skip-remaining 269 endchoice 270 close-elt 271 close-elt 272 repeat 273 close-elt 274 close-elt 275 else 276 -1 = ifnot ERR_X509_UNEXPECTED fail then 277 drop 278 then 279 280 close-elt 281 282 \ signature algorithm 283 read-sequence-open 284 read-OID if 285 choice 286 sha1WithRSAEncryption eqOID uf 2 KEYTYPE_RSA enduf 287 sha224WithRSAEncryption eqOID uf 3 KEYTYPE_RSA enduf 288 sha256WithRSAEncryption eqOID uf 4 KEYTYPE_RSA enduf 289 sha384WithRSAEncryption eqOID uf 5 KEYTYPE_RSA enduf 290 sha512WithRSAEncryption eqOID uf 6 KEYTYPE_RSA enduf 291 292 ecdsa-with-SHA1 eqOID uf 2 KEYTYPE_EC enduf 293 ecdsa-with-SHA224 eqOID uf 3 KEYTYPE_EC enduf 294 ecdsa-with-SHA256 eqOID uf 4 KEYTYPE_EC enduf 295 ecdsa-with-SHA384 eqOID uf 5 KEYTYPE_EC enduf 296 ecdsa-with-SHA512 eqOID uf 6 KEYTYPE_EC enduf 297 298 0 0 299 endchoice 300 else 301 0 0 302 then 303 addr-signer_key_type set8 304 addr-signer_hash_id set8 305 skip-close-elt 306 \ read-sequence-open skip-close-elt 307 308 \ signature value 309 read-bits-open skip-close-elt 310 311 \ Close the outer SEQUENCE. 312 close-elt 313 drop 314 315 \ Mark the decoding as successful. 316 1 addr-decoded set8 317 318 \ Read one byte, then fail: if the read succeeds, then there is 319 \ some trailing byte. 320 read8-nc ERR_X509_EXTRA_ELEMENT fail 321 ; 322