1 /* 2 * PKCS #1 (RSA Encryption) 3 * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "crypto/crypto.h" 13 #include "rsa.h" 14 #include "asn1.h" 15 #include "pkcs1.h" 16 17 18 static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, 19 const u8 *in, size_t inlen, 20 u8 *out, size_t *outlen) 21 { 22 size_t ps_len; 23 u8 *pos; 24 25 /* 26 * PKCS #1 v1.5, 8.1: 27 * 28 * EB = 00 || BT || PS || 00 || D 29 * BT = 00 or 01 for private-key operation; 02 for public-key operation 30 * PS = k-3-||D||; at least eight octets 31 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) 32 * k = length of modulus in octets (modlen) 33 */ 34 35 if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { 36 wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " 37 "lengths (modlen=%lu outlen=%lu inlen=%lu)", 38 __func__, (unsigned long) modlen, 39 (unsigned long) *outlen, 40 (unsigned long) inlen); 41 return -1; 42 } 43 44 pos = out; 45 *pos++ = 0x00; 46 *pos++ = block_type; /* BT */ 47 ps_len = modlen - inlen - 3; 48 switch (block_type) { 49 case 0: 50 os_memset(pos, 0x00, ps_len); 51 pos += ps_len; 52 break; 53 case 1: 54 os_memset(pos, 0xff, ps_len); 55 pos += ps_len; 56 break; 57 case 2: 58 if (os_get_random(pos, ps_len) < 0) { 59 wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " 60 "random data for PS", __func__); 61 return -1; 62 } 63 while (ps_len--) { 64 if (*pos == 0x00) 65 *pos = 0x01; 66 pos++; 67 } 68 break; 69 default: 70 wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " 71 "%d", __func__, block_type); 72 return -1; 73 } 74 *pos++ = 0x00; 75 os_memcpy(pos, in, inlen); /* D */ 76 77 return 0; 78 } 79 80 81 int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, 82 int use_private, const u8 *in, size_t inlen, 83 u8 *out, size_t *outlen) 84 { 85 size_t modlen; 86 87 modlen = crypto_rsa_get_modulus_len(key); 88 89 if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, 90 out, outlen) < 0) 91 return -1; 92 93 return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private); 94 } 95 96 97 int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, 98 const u8 *in, size_t inlen, 99 u8 *out, size_t *outlen) 100 { 101 int res; 102 u8 *pos, *end; 103 104 res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1); 105 if (res) 106 return res; 107 108 if (*outlen < 2 || out[0] != 0 || out[1] != 2) 109 return -1; 110 111 /* Skip PS (pseudorandom non-zero octets) */ 112 pos = out + 2; 113 end = out + *outlen; 114 while (*pos && pos < end) 115 pos++; 116 if (pos == end) 117 return -1; 118 if (pos - out - 2 < 8) { 119 /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ 120 wpa_printf(MSG_INFO, "LibTomCrypt: Too short padding"); 121 return -1; 122 } 123 pos++; 124 125 *outlen -= pos - out; 126 127 /* Strip PKCS #1 header */ 128 os_memmove(out, pos, *outlen); 129 130 return 0; 131 } 132 133 134 int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, 135 const u8 *crypt, size_t crypt_len, 136 u8 *plain, size_t *plain_len) 137 { 138 size_t len; 139 u8 *pos; 140 141 len = *plain_len; 142 if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0) 143 return -1; 144 145 /* 146 * PKCS #1 v1.5, 8.1: 147 * 148 * EB = 00 || BT || PS || 00 || D 149 * BT = 00 or 01 150 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01) 151 * k = length of modulus in octets 152 * 153 * Based on 10.1.3, "The block type shall be 01" for a signature. 154 */ 155 156 if (len < 3 + 8 + 16 /* min hash len */ || 157 plain[0] != 0x00 || plain[1] != 0x01) { 158 wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " 159 "structure"); 160 wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len); 161 return -1; 162 } 163 164 pos = plain + 3; 165 /* BT = 01 */ 166 if (plain[2] != 0xff) { 167 wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " 168 "PS (BT=01)"); 169 wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len); 170 return -1; 171 } 172 while (pos < plain + len && *pos == 0xff) 173 pos++; 174 175 if (pos - plain - 2 < 8) { 176 /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ 177 wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " 178 "padding"); 179 wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len); 180 return -1; 181 } 182 183 if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { 184 wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " 185 "structure (2)"); 186 wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len); 187 return -1; 188 } 189 pos++; 190 len -= pos - plain; 191 192 /* Strip PKCS #1 header */ 193 os_memmove(plain, pos, len); 194 *plain_len = len; 195 196 return 0; 197 } 198 199 200 int pkcs1_v15_sig_ver(struct crypto_public_key *pk, 201 const u8 *s, size_t s_len, 202 const struct asn1_oid *hash_alg, 203 const u8 *hash, size_t hash_len) 204 { 205 int res; 206 u8 *decrypted; 207 size_t decrypted_len; 208 const u8 *pos, *end, *next, *da_end; 209 struct asn1_hdr hdr; 210 struct asn1_oid oid; 211 212 decrypted = os_malloc(s_len); 213 if (decrypted == NULL) 214 return -1; 215 decrypted_len = s_len; 216 res = crypto_public_key_decrypt_pkcs1(pk, s, s_len, decrypted, 217 &decrypted_len); 218 if (res < 0) { 219 wpa_printf(MSG_INFO, "PKCS #1: RSA decrypt failed"); 220 os_free(decrypted); 221 return -1; 222 } 223 wpa_hexdump(MSG_DEBUG, "Decrypted(S)", decrypted, decrypted_len); 224 225 /* 226 * PKCS #1 v1.5, 10.1.2: 227 * 228 * DigestInfo ::= SEQUENCE { 229 * digestAlgorithm DigestAlgorithmIdentifier, 230 * digest Digest 231 * } 232 * 233 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier 234 * 235 * Digest ::= OCTET STRING 236 * 237 */ 238 if (asn1_get_next(decrypted, decrypted_len, &hdr) < 0 || 239 !asn1_is_sequence(&hdr)) { 240 asn1_unexpected(&hdr, 241 "PKCS #1: Expected SEQUENCE (DigestInfo)"); 242 os_free(decrypted); 243 return -1; 244 } 245 wpa_hexdump(MSG_MSGDUMP, "PKCS #1: DigestInfo", 246 hdr.payload, hdr.length); 247 248 pos = hdr.payload; 249 end = pos + hdr.length; 250 251 /* 252 * X.509: 253 * AlgorithmIdentifier ::= SEQUENCE { 254 * algorithm OBJECT IDENTIFIER, 255 * parameters ANY DEFINED BY algorithm OPTIONAL 256 * } 257 */ 258 259 if (asn1_get_next(pos, end - pos, &hdr) < 0 || 260 !asn1_is_sequence(&hdr)) { 261 asn1_unexpected(&hdr, 262 "PKCS #1: Expected SEQUENCE (AlgorithmIdentifier)"); 263 os_free(decrypted); 264 return -1; 265 } 266 wpa_hexdump(MSG_MSGDUMP, "PKCS #1: DigestAlgorithmIdentifier", 267 hdr.payload, hdr.length); 268 da_end = hdr.payload + hdr.length; 269 270 if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) { 271 wpa_printf(MSG_DEBUG, 272 "PKCS #1: Failed to parse digestAlgorithm"); 273 os_free(decrypted); 274 return -1; 275 } 276 wpa_hexdump(MSG_MSGDUMP, "PKCS #1: Digest algorithm parameters", 277 next, da_end - next); 278 279 /* 280 * RFC 5754: The correct encoding for the SHA2 algorithms would be to 281 * omit the parameters, but there are implementation that encode these 282 * as a NULL element. Allow these two cases and reject anything else. 283 */ 284 if (da_end > next && 285 (asn1_get_next(next, da_end - next, &hdr) < 0 || 286 !asn1_is_null(&hdr) || 287 hdr.payload + hdr.length != da_end)) { 288 wpa_printf(MSG_DEBUG, 289 "PKCS #1: Unexpected digest algorithm parameters"); 290 os_free(decrypted); 291 return -1; 292 } 293 294 if (!asn1_oid_equal(&oid, hash_alg)) { 295 char txt[100], txt2[100]; 296 asn1_oid_to_str(&oid, txt, sizeof(txt)); 297 asn1_oid_to_str(hash_alg, txt2, sizeof(txt2)); 298 wpa_printf(MSG_DEBUG, 299 "PKCS #1: Hash alg OID mismatch: was %s, expected %s", 300 txt, txt2); 301 os_free(decrypted); 302 return -1; 303 } 304 305 /* Digest ::= OCTET STRING */ 306 pos = da_end; 307 308 if (asn1_get_next(pos, end - pos, &hdr) < 0 || 309 !asn1_is_octetstring(&hdr)) { 310 asn1_unexpected(&hdr, 311 "PKCS #1: Expected OCTETSTRING (Digest)"); 312 os_free(decrypted); 313 return -1; 314 } 315 wpa_hexdump(MSG_MSGDUMP, "PKCS #1: Decrypted Digest", 316 hdr.payload, hdr.length); 317 318 if (hdr.length != hash_len || 319 os_memcmp_const(hdr.payload, hash, hdr.length) != 0) { 320 wpa_printf(MSG_INFO, "PKCS #1: Digest value does not match calculated hash"); 321 os_free(decrypted); 322 return -1; 323 } 324 325 os_free(decrypted); 326 327 if (hdr.payload + hdr.length != decrypted + decrypted_len) { 328 wpa_printf(MSG_INFO, 329 "PKCS #1: Extra data after signature - reject"); 330 331 wpa_hexdump(MSG_DEBUG, "PKCS #1: Extra data", 332 hdr.payload + hdr.length, 333 decrypted + decrypted_len - hdr.payload - 334 hdr.length); 335 return -1; 336 } 337 338 return 0; 339 } 340