skey_decoder.t0
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 23 preamble { 24 25 #include "inner.h" 26 27 #define CTX ((br_skey_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_skey_decoder_context, cpu))) 28 #define CONTEXT_NAME br_skey_decoder_context 29 30 /* see bearssl_x509.h */ 31 void 32 br_skey_decoder_init(br_skey_decoder_context *ctx) 33 { 34 memset(ctx, 0, sizeof *ctx); 35 ctx->cpu.dp = &ctx->dp_stack[0]; 36 ctx->cpu.rp = &ctx->rp_stack[0]; 37 br_skey_decoder_init_main(&ctx->cpu); 38 br_skey_decoder_run(&ctx->cpu); 39 } 40 41 /* see bearssl_x509.h */ 42 void 43 br_skey_decoder_push(br_skey_decoder_context *ctx, 44 const void *data, size_t len) 45 { 46 ctx->hbuf = data; 47 ctx->hlen = len; 48 br_skey_decoder_run(&ctx->cpu); 49 } 50 51 } 52 53 addr: key_type 54 addr: key_data 55 56 cc: read8-low ( -- x ) { 57 if (CTX->hlen == 0) { 58 T0_PUSHi(-1); 59 } else { 60 CTX->hlen --; 61 T0_PUSH(*CTX->hbuf ++); 62 } 63 } 64 65 cc: read-blob-inner ( addr len -- addr len ) { 66 uint32_t len = T0_POP(); 67 uint32_t addr = T0_POP(); 68 size_t clen = CTX->hlen; 69 if (clen > len) { 70 clen = (size_t)len; 71 } 72 if (addr != 0) { 73 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); 74 } 75 CTX->hbuf += clen; 76 CTX->hlen -= clen; 77 T0_PUSH(addr + clen); 78 T0_PUSH(len - clen); 79 } 80 81 \ Get the length of the key_data buffer. 82 : len-key_data 83 CX 0 8191 { 3 * BR_X509_BUFSIZE_SIG } ; 84 85 \ Get the address and length for the key_data buffer. 86 : addr-len-key_data ( -- addr len ) 87 addr-key_data len-key_data ; 88 89 \ Set the private key (RSA). 90 cc: set-rsa-key ( n_bitlen plen qlen dplen dqlen iqlen -- ) { 91 size_t iqlen = T0_POP(); 92 size_t dqlen = T0_POP(); 93 size_t dplen = T0_POP(); 94 size_t qlen = T0_POP(); 95 size_t plen = T0_POP(); 96 uint32_t n_bitlen = T0_POP(); 97 size_t off; 98 99 CTX->key.rsa.n_bitlen = n_bitlen; 100 CTX->key.rsa.p = CTX->key_data; 101 CTX->key.rsa.plen = plen; 102 off = plen; 103 CTX->key.rsa.q = CTX->key_data + off; 104 CTX->key.rsa.qlen = qlen; 105 off += qlen; 106 CTX->key.rsa.dp = CTX->key_data + off; 107 CTX->key.rsa.dplen = dplen; 108 off += dplen; 109 CTX->key.rsa.dq = CTX->key_data + off; 110 CTX->key.rsa.dqlen = dqlen; 111 off += dqlen; 112 CTX->key.rsa.iq = CTX->key_data + off; 113 CTX->key.rsa.iqlen = iqlen; 114 } 115 116 \ Set the private key (EC). 117 cc: set-ec-key ( curve xlen -- ) { 118 size_t xlen = T0_POP(); 119 uint32_t curve = T0_POP(); 120 CTX->key.ec.curve = curve; 121 CTX->key.ec.x = CTX->key_data; 122 CTX->key.ec.xlen = xlen; 123 } 124 125 \ Get the bit length for an integer (unsigned). 126 : int-bit-length ( x -- bitlen ) 127 0 swap 128 begin dup while 1 u>> swap 1+ swap repeat 129 drop ; 130 131 \ Read an INTEGER into the key_data buffer, but then ignore it. 132 : read-integer-ignore ( lim -- lim ) 133 addr-len-key_data read-integer drop ; 134 135 \ Read an INTEGER into the key_data buffer, at the provided offset. 136 \ Returned value is the integer length (in bytes). 137 : read-integer-off ( lim off -- lim dlen ) 138 dup addr-len-key_data rot - swap rot + swap read-integer ; 139 140 \ Decode RSA key, starting with the SEQUENCE tag. 141 : decode-RSA ( lim -- lim ) 142 read-sequence-open 143 144 \ Version should be 0. 145 read-tag 0x02 check-tag-primitive read-small-int-value if 146 ERR_X509_UNSUPPORTED fail 147 then 148 149 \ Read tag for the modulus; should be INTEGER. Then use the 150 \ decode-RSA-next function for the remainder of the key. 151 read-tag 0x02 check-tag-primitive 152 decode-RSA-next 153 154 \ Close the SEQUENCE. 155 close-elt ; 156 157 \ Decode RSA key; the version, and the tag for the modulus, have been 158 \ read. 159 : decode-RSA-next ( lim -- lim ) 160 \ Modulus: we read it but we do not keep it; we merely gather 161 \ the modulus bit length. 162 addr-len-key_data read-integer-next 163 dup ifnot ERR_X509_UNEXPECTED fail then 164 1- 3 << addr-key_data get8 int-bit-length + { n_bitlen } 165 166 \ Public exponent: read but skip. 167 read-integer-ignore 168 169 \ Private exponent: read but skip. 170 read-integer-ignore 171 172 \ First prime factor. 173 addr-len-key_data read-integer dup dup { off plen } 174 175 \ Second prime factor. 176 read-integer-off dup { qlen } off + dup >off 177 178 \ First reduced private exponent. 179 read-integer-off dup { dplen } off + dup >off 180 181 \ Second reduced private exponent. 182 read-integer-off dup { dqlen } off + dup >off 183 184 \ CRT coefficient. 185 read-integer-off { iqlen } 186 187 \ Set RSA key. 188 n_bitlen plen qlen dplen dqlen iqlen set-rsa-key 189 190 \ The caller will close the sequence, thereby validating that there 191 \ is no extra field. 192 ; 193 194 \ Decode an EC key, starting with the SEQUENCE tag. 195 : decode-EC ( lim curve -- lim ) 196 { curve } 197 read-sequence-open 198 199 \ Version should be 1. 200 read-tag 0x02 check-tag-primitive read-small-int-value 1- if 201 ERR_X509_UNSUPPORTED fail 202 then 203 204 \ Read tag for the private key; should be OCTET STRING. Then use the 205 \ decode-EC-next function for the remainder of the key. 206 read-tag 0x04 check-tag-primitive 207 curve decode-EC-next 208 209 \ Close the SEQUENCE. 210 close-elt ; 211 212 \ Decode an EC key; the version, and the tag for the OCTET STRING, have 213 \ already been read. The curve ID is provided (0 if unknown). 214 : decode-EC-next ( lim curve -- lim ) 215 { curve } 216 217 \ Read the private key proper. 218 read-length-open-elt 219 dup dup { xlen } len-key_data > if ERR_X509_UNSUPPORTED fail then 220 addr-key_data read-blob 221 222 \ Next element might be the curve identifier. 223 read-tag-or-end 224 case 225 226 \ End of structure. 227 -1 of drop endof 228 229 \ Curve parameters; we support only named curves. 230 0x20 of 231 check-constructed read-length-open-elt 232 read-curve-ID 233 curve if 234 curve <> if ERR_X509_INVALID_VALUE fail then 235 else 236 >curve 237 then 238 close-elt 239 endof 240 241 \ Public key. We ignore it. 242 0x21 of check-constructed endof 243 244 ERR_X509_UNSUPPORTED fail 245 endcase 246 skip-remaining 247 248 \ The curve must have been defined one way or another. 249 curve ifnot ERR_X509_UNSUPPORTED fail then 250 251 \ Set the EC key. 252 curve xlen set-ec-key 253 254 \ The caller will close the sequence. 255 ; 256 257 \ Decode a PKCS#8 object. The version and the tag for the AlgorithmIdentifier 258 \ structure have already been read. This function returns the key type. 259 : decode-PKCS8-next ( lim -- lim keytype ) 260 \ Decode the AlgorithmIdentifier. 261 read-length-open-elt 262 read-OID ifnot ERR_X509_UNSUPPORTED fail then 263 { ; is-rsa curve } 264 choice 265 rsaEncryption eqOID uf 266 \ RSA private key. We ignore the parameters. 267 skip-remaining -1 >is-rsa 268 enduf 269 id-ecPublicKey eqOID uf 270 \ EC private key. Parameters, if present, shall 271 \ identify the curve. 272 0 >is-rsa 273 dup if read-curve-ID else 0 then >curve 274 enduf 275 276 ERR_X509_UNSUPPORTED fail 277 endchoice 278 close-elt 279 280 \ Open private key value and decode it. 281 read-tag 0x04 check-tag-primitive 282 read-length-open-elt 283 is-rsa if 284 decode-RSA 285 else 286 curve decode-EC 287 then 288 close-elt 289 290 \ We ignore any extra field, i.e. attributes or public key. 291 skip-remaining 292 293 \ Return the key type. 294 is-rsa if KEYTYPE_RSA else KEYTYPE_EC then 295 ; 296 297 \ Decode a private key. 298 : main ( -- ! ) 299 \ RSA private key format is defined in PKCS#1 (RFC 3447): 300 \ RSAPrivateKey ::= SEQUENCE { 301 \ version INTEGER, -- 0 or 1 302 \ n INTEGER, 303 \ e INTEGER, 304 \ d INTEGER, 305 \ p INTEGER, 306 \ q INTEGER, 307 \ dp INTEGER, 308 \ dq INTEGER, 309 \ iq INTEGER, 310 \ other OtherPrimeInfos OPTIONAL 311 \ } 312 \ We do not support keys with more than two primes (these have 313 \ version 1); thus, we expect the version field to be 0, and 314 \ the 'other' field to be absent. 315 \ 316 \ EC private key format is defined in RFC 5915: 317 \ ECPrivateKey ::= SEQUENCE { 318 \ version INTEGER, -- always 1 319 \ privateKey OCTET STRING, 320 \ parameters [0] EXPLICIT OBJECT IDENTIFIER OPTIONAL, 321 \ publicKey [1] EXPLICIT BIT STRING OPTIONAL 322 \ } 323 \ The "parameters" might conceptually be a complex curve description 324 \ structure but we support only named curves. The private key 325 \ contents are the unsigned big-endian encoding of the key value, 326 \ which is exactly what we want. 327 \ 328 \ PKCS#8 (unencrypted) is: 329 \ OneAsymmetricKey ::= SEQUENCE { 330 \ version INTEGER, -- 0 or 1 331 \ algorithm AlgorithmIdentifier, 332 \ privateKey OCTET STRING, 333 \ attributes [0] IMPLICIT Attributes OPTIONAL, 334 \ publicKey [1] IMPLICIT BIT STRING OPTIONAL 335 \ } 336 \ The 'publicKey' field is an add-on from RFC 5958 and may be 337 \ present only if the 'version' is v2 (i.e. has value 1). We 338 \ ignore it anyway. 339 340 \ An arbitrary upper limit on the private key size. 341 0xFFFFFF 342 343 \ Open the outer SEQUENCE. 344 read-sequence-open 345 346 \ All our schemas begin with a small INTEGER which is either 0 or 347 \ 1. We don't care which it is. 348 read-tag 0x02 check-tag-primitive read-small-int-value 1 > if 349 ERR_X509_UNSUPPORTED fail 350 then 351 352 \ Get next tag: it should be either an INTEGER (RSA private key), 353 \ an OCTET STRING (EC private key), or a SEQUENCE (for an 354 \ AlgorithmIdentifier, in a PKCS#8 object). 355 read-tag 356 case 357 0x02 of check-primitive decode-RSA-next KEYTYPE_RSA endof 358 0x04 of check-primitive 0 decode-EC-next KEYTYPE_EC endof 359 0x10 of check-constructed decode-PKCS8-next endof 360 ERR_X509_UNSUPPORTED fail 361 endcase 362 { key-type } 363 364 \ Close the SEQUENCE. 365 close-elt 366 367 \ Set the key type, which marks the decoding as a success. 368 key-type addr-key_type set8 369 370 \ Read one byte, then fail: if the read succeeds, then there is 371 \ some trailing byte. 372 read8-nc ERR_X509_EXTRA_ELEMENT fail 373 ;