139beb93cSSam Leffler /* 239beb93cSSam Leffler * RSA 339beb93cSSam Leffler * Copyright (c) 2006, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 1239beb93cSSam Leffler #include "asn1.h" 1339beb93cSSam Leffler #include "bignum.h" 1439beb93cSSam Leffler #include "rsa.h" 1539beb93cSSam Leffler 1639beb93cSSam Leffler 1739beb93cSSam Leffler struct crypto_rsa_key { 1839beb93cSSam Leffler int private_key; /* whether private key is set */ 1939beb93cSSam Leffler struct bignum *n; /* modulus (p * q) */ 2039beb93cSSam Leffler struct bignum *e; /* public exponent */ 2139beb93cSSam Leffler /* The following parameters are available only if private_key is set */ 2239beb93cSSam Leffler struct bignum *d; /* private exponent */ 2339beb93cSSam Leffler struct bignum *p; /* prime p (factor of n) */ 2439beb93cSSam Leffler struct bignum *q; /* prime q (factor of n) */ 2539beb93cSSam Leffler struct bignum *dmp1; /* d mod (p - 1); CRT exponent */ 2639beb93cSSam Leffler struct bignum *dmq1; /* d mod (q - 1); CRT exponent */ 2739beb93cSSam Leffler struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */ 2839beb93cSSam Leffler }; 2939beb93cSSam Leffler 3039beb93cSSam Leffler 3139beb93cSSam Leffler static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end, 3239beb93cSSam Leffler struct bignum *num) 3339beb93cSSam Leffler { 3439beb93cSSam Leffler struct asn1_hdr hdr; 3539beb93cSSam Leffler 3639beb93cSSam Leffler if (pos == NULL) 3739beb93cSSam Leffler return NULL; 3839beb93cSSam Leffler 3939beb93cSSam Leffler if (asn1_get_next(pos, end - pos, &hdr) < 0 || 4039beb93cSSam Leffler hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { 4139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d " 4239beb93cSSam Leffler "tag 0x%x", hdr.class, hdr.tag); 4339beb93cSSam Leffler return NULL; 4439beb93cSSam Leffler } 4539beb93cSSam Leffler 4639beb93cSSam Leffler if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) { 4739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER"); 4839beb93cSSam Leffler return NULL; 4939beb93cSSam Leffler } 5039beb93cSSam Leffler 5139beb93cSSam Leffler return hdr.payload + hdr.length; 5239beb93cSSam Leffler } 5339beb93cSSam Leffler 5439beb93cSSam Leffler 5539beb93cSSam Leffler /** 5639beb93cSSam Leffler * crypto_rsa_import_public_key - Import an RSA public key 5739beb93cSSam Leffler * @buf: Key buffer (DER encoded RSA public key) 5839beb93cSSam Leffler * @len: Key buffer length in bytes 5939beb93cSSam Leffler * Returns: Pointer to the public key or %NULL on failure 6039beb93cSSam Leffler */ 6139beb93cSSam Leffler struct crypto_rsa_key * 6239beb93cSSam Leffler crypto_rsa_import_public_key(const u8 *buf, size_t len) 6339beb93cSSam Leffler { 6439beb93cSSam Leffler struct crypto_rsa_key *key; 6539beb93cSSam Leffler struct asn1_hdr hdr; 6639beb93cSSam Leffler const u8 *pos, *end; 6739beb93cSSam Leffler 6839beb93cSSam Leffler key = os_zalloc(sizeof(*key)); 6939beb93cSSam Leffler if (key == NULL) 7039beb93cSSam Leffler return NULL; 7139beb93cSSam Leffler 7239beb93cSSam Leffler key->n = bignum_init(); 7339beb93cSSam Leffler key->e = bignum_init(); 7439beb93cSSam Leffler if (key->n == NULL || key->e == NULL) { 7539beb93cSSam Leffler crypto_rsa_free(key); 7639beb93cSSam Leffler return NULL; 7739beb93cSSam Leffler } 7839beb93cSSam Leffler 7939beb93cSSam Leffler /* 8039beb93cSSam Leffler * PKCS #1, 7.1: 8139beb93cSSam Leffler * RSAPublicKey ::= SEQUENCE { 8239beb93cSSam Leffler * modulus INTEGER, -- n 8339beb93cSSam Leffler * publicExponent INTEGER -- e 8439beb93cSSam Leffler * } 8539beb93cSSam Leffler */ 8639beb93cSSam Leffler 8739beb93cSSam Leffler if (asn1_get_next(buf, len, &hdr) < 0 || 8839beb93cSSam Leffler hdr.class != ASN1_CLASS_UNIVERSAL || 8939beb93cSSam Leffler hdr.tag != ASN1_TAG_SEQUENCE) { 9039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " 9139beb93cSSam Leffler "(public key) - found class %d tag 0x%x", 9239beb93cSSam Leffler hdr.class, hdr.tag); 9339beb93cSSam Leffler goto error; 9439beb93cSSam Leffler } 9539beb93cSSam Leffler pos = hdr.payload; 9639beb93cSSam Leffler end = pos + hdr.length; 9739beb93cSSam Leffler 9839beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->n); 9939beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->e); 10039beb93cSSam Leffler 10139beb93cSSam Leffler if (pos == NULL) 10239beb93cSSam Leffler goto error; 10339beb93cSSam Leffler 10439beb93cSSam Leffler if (pos != end) { 10539beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, 10639beb93cSSam Leffler "RSA: Extra data in public key SEQUENCE", 10739beb93cSSam Leffler pos, end - pos); 10839beb93cSSam Leffler goto error; 10939beb93cSSam Leffler } 11039beb93cSSam Leffler 11139beb93cSSam Leffler return key; 11239beb93cSSam Leffler 11339beb93cSSam Leffler error: 11439beb93cSSam Leffler crypto_rsa_free(key); 11539beb93cSSam Leffler return NULL; 11639beb93cSSam Leffler } 11739beb93cSSam Leffler 11839beb93cSSam Leffler 11939beb93cSSam Leffler /** 12039beb93cSSam Leffler * crypto_rsa_import_private_key - Import an RSA private key 12139beb93cSSam Leffler * @buf: Key buffer (DER encoded RSA private key) 12239beb93cSSam Leffler * @len: Key buffer length in bytes 12339beb93cSSam Leffler * Returns: Pointer to the private key or %NULL on failure 12439beb93cSSam Leffler */ 12539beb93cSSam Leffler struct crypto_rsa_key * 12639beb93cSSam Leffler crypto_rsa_import_private_key(const u8 *buf, size_t len) 12739beb93cSSam Leffler { 12839beb93cSSam Leffler struct crypto_rsa_key *key; 12939beb93cSSam Leffler struct bignum *zero; 13039beb93cSSam Leffler struct asn1_hdr hdr; 13139beb93cSSam Leffler const u8 *pos, *end; 13239beb93cSSam Leffler 13339beb93cSSam Leffler key = os_zalloc(sizeof(*key)); 13439beb93cSSam Leffler if (key == NULL) 13539beb93cSSam Leffler return NULL; 13639beb93cSSam Leffler 13739beb93cSSam Leffler key->private_key = 1; 13839beb93cSSam Leffler 13939beb93cSSam Leffler key->n = bignum_init(); 14039beb93cSSam Leffler key->e = bignum_init(); 14139beb93cSSam Leffler key->d = bignum_init(); 14239beb93cSSam Leffler key->p = bignum_init(); 14339beb93cSSam Leffler key->q = bignum_init(); 14439beb93cSSam Leffler key->dmp1 = bignum_init(); 14539beb93cSSam Leffler key->dmq1 = bignum_init(); 14639beb93cSSam Leffler key->iqmp = bignum_init(); 14739beb93cSSam Leffler 14839beb93cSSam Leffler if (key->n == NULL || key->e == NULL || key->d == NULL || 14939beb93cSSam Leffler key->p == NULL || key->q == NULL || key->dmp1 == NULL || 15039beb93cSSam Leffler key->dmq1 == NULL || key->iqmp == NULL) { 15139beb93cSSam Leffler crypto_rsa_free(key); 15239beb93cSSam Leffler return NULL; 15339beb93cSSam Leffler } 15439beb93cSSam Leffler 15539beb93cSSam Leffler /* 15639beb93cSSam Leffler * PKCS #1, 7.2: 15739beb93cSSam Leffler * RSAPrivateKey ::= SEQUENCE { 15839beb93cSSam Leffler * version Version, 15939beb93cSSam Leffler * modulus INTEGER, -- n 16039beb93cSSam Leffler * publicExponent INTEGER, -- e 16139beb93cSSam Leffler * privateExponent INTEGER, -- d 16239beb93cSSam Leffler * prime1 INTEGER, -- p 16339beb93cSSam Leffler * prime2 INTEGER, -- q 16439beb93cSSam Leffler * exponent1 INTEGER, -- d mod (p-1) 16539beb93cSSam Leffler * exponent2 INTEGER, -- d mod (q-1) 16639beb93cSSam Leffler * coefficient INTEGER -- (inverse of q) mod p 16739beb93cSSam Leffler * } 16839beb93cSSam Leffler * 16939beb93cSSam Leffler * Version ::= INTEGER -- shall be 0 for this version of the standard 17039beb93cSSam Leffler */ 17139beb93cSSam Leffler if (asn1_get_next(buf, len, &hdr) < 0 || 17239beb93cSSam Leffler hdr.class != ASN1_CLASS_UNIVERSAL || 17339beb93cSSam Leffler hdr.tag != ASN1_TAG_SEQUENCE) { 17439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " 17539beb93cSSam Leffler "(public key) - found class %d tag 0x%x", 17639beb93cSSam Leffler hdr.class, hdr.tag); 17739beb93cSSam Leffler goto error; 17839beb93cSSam Leffler } 17939beb93cSSam Leffler pos = hdr.payload; 18039beb93cSSam Leffler end = pos + hdr.length; 18139beb93cSSam Leffler 18239beb93cSSam Leffler zero = bignum_init(); 18339beb93cSSam Leffler if (zero == NULL) 18439beb93cSSam Leffler goto error; 18539beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, zero); 18639beb93cSSam Leffler if (pos == NULL || bignum_cmp_d(zero, 0) != 0) { 18739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the " 18839beb93cSSam Leffler "beginning of private key; not found"); 18939beb93cSSam Leffler bignum_deinit(zero); 19039beb93cSSam Leffler goto error; 19139beb93cSSam Leffler } 19239beb93cSSam Leffler bignum_deinit(zero); 19339beb93cSSam Leffler 19439beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->n); 19539beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->e); 19639beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->d); 19739beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->p); 19839beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->q); 19939beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->dmp1); 20039beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->dmq1); 20139beb93cSSam Leffler pos = crypto_rsa_parse_integer(pos, end, key->iqmp); 20239beb93cSSam Leffler 20339beb93cSSam Leffler if (pos == NULL) 20439beb93cSSam Leffler goto error; 20539beb93cSSam Leffler 20639beb93cSSam Leffler if (pos != end) { 20739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, 20839beb93cSSam Leffler "RSA: Extra data in public key SEQUENCE", 20939beb93cSSam Leffler pos, end - pos); 21039beb93cSSam Leffler goto error; 21139beb93cSSam Leffler } 21239beb93cSSam Leffler 21339beb93cSSam Leffler return key; 21439beb93cSSam Leffler 21539beb93cSSam Leffler error: 21639beb93cSSam Leffler crypto_rsa_free(key); 21739beb93cSSam Leffler return NULL; 21839beb93cSSam Leffler } 21939beb93cSSam Leffler 22039beb93cSSam Leffler 22139beb93cSSam Leffler /** 22239beb93cSSam Leffler * crypto_rsa_get_modulus_len - Get the modulus length of the RSA key 22339beb93cSSam Leffler * @key: RSA key 22439beb93cSSam Leffler * Returns: Modulus length of the key 22539beb93cSSam Leffler */ 22639beb93cSSam Leffler size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key) 22739beb93cSSam Leffler { 22839beb93cSSam Leffler return bignum_get_unsigned_bin_len(key->n); 22939beb93cSSam Leffler } 23039beb93cSSam Leffler 23139beb93cSSam Leffler 23239beb93cSSam Leffler /** 23339beb93cSSam Leffler * crypto_rsa_exptmod - RSA modular exponentiation 23439beb93cSSam Leffler * @in: Input data 23539beb93cSSam Leffler * @inlen: Input data length 23639beb93cSSam Leffler * @out: Buffer for output data 23739beb93cSSam Leffler * @outlen: Maximum size of the output buffer and used size on success 23839beb93cSSam Leffler * @key: RSA key 23939beb93cSSam Leffler * @use_private: 1 = Use RSA private key, 0 = Use RSA public key 24039beb93cSSam Leffler * Returns: 0 on success, -1 on failure 24139beb93cSSam Leffler */ 24239beb93cSSam Leffler int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, 24339beb93cSSam Leffler struct crypto_rsa_key *key, int use_private) 24439beb93cSSam Leffler { 24539beb93cSSam Leffler struct bignum *tmp, *a = NULL, *b = NULL; 24639beb93cSSam Leffler int ret = -1; 24739beb93cSSam Leffler size_t modlen; 24839beb93cSSam Leffler 24939beb93cSSam Leffler if (use_private && !key->private_key) 25039beb93cSSam Leffler return -1; 25139beb93cSSam Leffler 25239beb93cSSam Leffler tmp = bignum_init(); 25339beb93cSSam Leffler if (tmp == NULL) 25439beb93cSSam Leffler return -1; 25539beb93cSSam Leffler 25639beb93cSSam Leffler if (bignum_set_unsigned_bin(tmp, in, inlen) < 0) 25739beb93cSSam Leffler goto error; 25839beb93cSSam Leffler if (bignum_cmp(key->n, tmp) < 0) { 25939beb93cSSam Leffler /* Too large input value for the RSA key modulus */ 26039beb93cSSam Leffler goto error; 26139beb93cSSam Leffler } 26239beb93cSSam Leffler 26339beb93cSSam Leffler if (use_private) { 26439beb93cSSam Leffler /* 26539beb93cSSam Leffler * Decrypt (or sign) using Chinese remainer theorem to speed 26639beb93cSSam Leffler * up calculation. This is equivalent to tmp = tmp^d mod n 26739beb93cSSam Leffler * (which would require more CPU to calculate directly). 26839beb93cSSam Leffler * 26939beb93cSSam Leffler * dmp1 = (1/e) mod (p-1) 27039beb93cSSam Leffler * dmq1 = (1/e) mod (q-1) 27139beb93cSSam Leffler * iqmp = (1/q) mod p, where p > q 27239beb93cSSam Leffler * m1 = c^dmp1 mod p 27339beb93cSSam Leffler * m2 = c^dmq1 mod q 27439beb93cSSam Leffler * h = q^-1 (m1 - m2) mod p 27539beb93cSSam Leffler * m = m2 + hq 27639beb93cSSam Leffler */ 27739beb93cSSam Leffler a = bignum_init(); 27839beb93cSSam Leffler b = bignum_init(); 27939beb93cSSam Leffler if (a == NULL || b == NULL) 28039beb93cSSam Leffler goto error; 28139beb93cSSam Leffler 28239beb93cSSam Leffler /* a = tmp^dmp1 mod p */ 28339beb93cSSam Leffler if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0) 28439beb93cSSam Leffler goto error; 28539beb93cSSam Leffler 28639beb93cSSam Leffler /* b = tmp^dmq1 mod q */ 28739beb93cSSam Leffler if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0) 28839beb93cSSam Leffler goto error; 28939beb93cSSam Leffler 29039beb93cSSam Leffler /* tmp = (a - b) * (1/q mod p) (mod p) */ 29139beb93cSSam Leffler if (bignum_sub(a, b, tmp) < 0 || 29239beb93cSSam Leffler bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0) 29339beb93cSSam Leffler goto error; 29439beb93cSSam Leffler 29539beb93cSSam Leffler /* tmp = b + q * tmp */ 29639beb93cSSam Leffler if (bignum_mul(tmp, key->q, tmp) < 0 || 29739beb93cSSam Leffler bignum_add(tmp, b, tmp) < 0) 29839beb93cSSam Leffler goto error; 29939beb93cSSam Leffler } else { 30039beb93cSSam Leffler /* Encrypt (or verify signature) */ 30139beb93cSSam Leffler /* tmp = tmp^e mod N */ 30239beb93cSSam Leffler if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0) 30339beb93cSSam Leffler goto error; 30439beb93cSSam Leffler } 30539beb93cSSam Leffler 30639beb93cSSam Leffler modlen = crypto_rsa_get_modulus_len(key); 30739beb93cSSam Leffler if (modlen > *outlen) { 30839beb93cSSam Leffler *outlen = modlen; 30939beb93cSSam Leffler goto error; 31039beb93cSSam Leffler } 31139beb93cSSam Leffler 31239beb93cSSam Leffler if (bignum_get_unsigned_bin_len(tmp) > modlen) 31339beb93cSSam Leffler goto error; /* should never happen */ 31439beb93cSSam Leffler 31539beb93cSSam Leffler *outlen = modlen; 31639beb93cSSam Leffler os_memset(out, 0, modlen); 31739beb93cSSam Leffler if (bignum_get_unsigned_bin( 31839beb93cSSam Leffler tmp, out + 31939beb93cSSam Leffler (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0) 32039beb93cSSam Leffler goto error; 32139beb93cSSam Leffler 32239beb93cSSam Leffler ret = 0; 32339beb93cSSam Leffler 32439beb93cSSam Leffler error: 32539beb93cSSam Leffler bignum_deinit(tmp); 32639beb93cSSam Leffler bignum_deinit(a); 32739beb93cSSam Leffler bignum_deinit(b); 32839beb93cSSam Leffler return ret; 32939beb93cSSam Leffler } 33039beb93cSSam Leffler 33139beb93cSSam Leffler 33239beb93cSSam Leffler /** 33339beb93cSSam Leffler * crypto_rsa_free - Free RSA key 33439beb93cSSam Leffler * @key: RSA key to be freed 33539beb93cSSam Leffler * 33639beb93cSSam Leffler * This function frees an RSA key imported with either 33739beb93cSSam Leffler * crypto_rsa_import_public_key() or crypto_rsa_import_private_key(). 33839beb93cSSam Leffler */ 33939beb93cSSam Leffler void crypto_rsa_free(struct crypto_rsa_key *key) 34039beb93cSSam Leffler { 34139beb93cSSam Leffler if (key) { 34239beb93cSSam Leffler bignum_deinit(key->n); 34339beb93cSSam Leffler bignum_deinit(key->e); 34439beb93cSSam Leffler bignum_deinit(key->d); 34539beb93cSSam Leffler bignum_deinit(key->p); 34639beb93cSSam Leffler bignum_deinit(key->q); 34739beb93cSSam Leffler bignum_deinit(key->dmp1); 34839beb93cSSam Leffler bignum_deinit(key->dmq1); 34939beb93cSSam Leffler bignum_deinit(key->iqmp); 35039beb93cSSam Leffler os_free(key); 35139beb93cSSam Leffler } 35239beb93cSSam Leffler } 353