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