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