1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis 2 * 3 * LibTomCrypt is a library that provides various cryptographic 4 * algorithms in a highly modular and flexible manner. 5 * 6 * The library is free for all purposes without any express 7 * guarantee it works. 8 * 9 * Tom St Denis, tomstdenis (at) gmail.com, http://libtomcrypt.com 10 */ 11 #include "tomcrypt.h" 12 13 /** 14 @file rsa_import.c 15 Import a PKCS RSA key, Tom St Denis 16 */ 17 18 #ifdef MRSA 19 20 /** 21 Import an RSAPublicKey or RSAPrivateKey [two-prime only, only support >= 1024-bit keys, defined in PKCS #1 v2.1] 22 @param in The packet to import from 23 @param inlen It's length (octets) 24 @param key [out] Destination for newly imported key 25 @return CRYPT_OK if successful, upon error allocated memory is freed 26 */ 27 int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) 28 { 29 int err; 30 void *zero; 31 unsigned char *tmpbuf; 32 unsigned long t, x, y, z, tmpoid[16]; 33 ltc_asn1_list ssl_pubkey_hashoid[2]; 34 ltc_asn1_list ssl_pubkey[2]; 35 36 LTC_ARGCHK(in != NULL); 37 LTC_ARGCHK(key != NULL); 38 LTC_ARGCHK(ltc_mp.name != NULL); 39 40 /* init key */ 41 if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, 42 &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) { 43 return err; 44 } 45 46 /* see if the OpenSSL DER format RSA public key will work */ 47 tmpbuf = XCALLOC(1, MAX_RSA_SIZE*8); 48 if (tmpbuf == NULL) { 49 err = CRYPT_MEM; 50 goto LBL_ERR; 51 } 52 53 /* this includes the internal hash ID and optional params (NULL in this case) */ 54 LTC_SET_ASN1(ssl_pubkey_hashoid, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0])); 55 LTC_SET_ASN1(ssl_pubkey_hashoid, 1, LTC_ASN1_NULL, NULL, 0); 56 57 /* the actual format of the SSL DER key is odd, it stores a RSAPublicKey in a **BIT** string ... so we have to extract it 58 then proceed to convert bit to octet 59 */ 60 LTC_SET_ASN1(ssl_pubkey, 0, LTC_ASN1_SEQUENCE, &ssl_pubkey_hashoid, 2); 61 LTC_SET_ASN1(ssl_pubkey, 1, LTC_ASN1_BIT_STRING, tmpbuf, MAX_RSA_SIZE*8); 62 63 if (der_decode_sequence(in, inlen, 64 ssl_pubkey, 2UL) == CRYPT_OK) { 65 66 /* ok now we have to reassemble the BIT STRING to an OCTET STRING. Thanks OpenSSL... */ 67 for (t = y = z = x = 0; x < ssl_pubkey[1].size; x++) { 68 y = (y << 1) | tmpbuf[x]; 69 if (++z == 8) { 70 tmpbuf[t++] = (unsigned char)y; 71 y = 0; 72 z = 0; 73 } 74 } 75 76 /* now it should be SEQUENCE { INTEGER, INTEGER } */ 77 if ((err = der_decode_sequence_multi(tmpbuf, t, 78 LTC_ASN1_INTEGER, 1UL, key->N, 79 LTC_ASN1_INTEGER, 1UL, key->e, 80 LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { 81 XFREE(tmpbuf); 82 goto LBL_ERR; 83 } 84 XFREE(tmpbuf); 85 key->type = PK_PUBLIC; 86 return CRYPT_OK; 87 } 88 XFREE(tmpbuf); 89 90 /* not SSL public key, try to match against PKCS #1 standards */ 91 if ((err = der_decode_sequence_multi(in, inlen, 92 LTC_ASN1_INTEGER, 1UL, key->N, 93 LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { 94 goto LBL_ERR; 95 } 96 97 if (mp_cmp_d(key->N, 0) == LTC_MP_EQ) { 98 if ((err = mp_init(&zero)) != CRYPT_OK) { 99 goto LBL_ERR; 100 } 101 /* it's a private key */ 102 if ((err = der_decode_sequence_multi(in, inlen, 103 LTC_ASN1_INTEGER, 1UL, zero, 104 LTC_ASN1_INTEGER, 1UL, key->N, 105 LTC_ASN1_INTEGER, 1UL, key->e, 106 LTC_ASN1_INTEGER, 1UL, key->d, 107 LTC_ASN1_INTEGER, 1UL, key->p, 108 LTC_ASN1_INTEGER, 1UL, key->q, 109 LTC_ASN1_INTEGER, 1UL, key->dP, 110 LTC_ASN1_INTEGER, 1UL, key->dQ, 111 LTC_ASN1_INTEGER, 1UL, key->qP, 112 LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { 113 mp_clear(zero); 114 goto LBL_ERR; 115 } 116 mp_clear(zero); 117 key->type = PK_PRIVATE; 118 } else if (mp_cmp_d(key->N, 1) == LTC_MP_EQ) { 119 /* we don't support multi-prime RSA */ 120 err = CRYPT_PK_INVALID_TYPE; 121 goto LBL_ERR; 122 } else { 123 /* it's a public key and we lack e */ 124 if ((err = der_decode_sequence_multi(in, inlen, 125 LTC_ASN1_INTEGER, 1UL, key->N, 126 LTC_ASN1_INTEGER, 1UL, key->e, 127 LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { 128 goto LBL_ERR; 129 } 130 key->type = PK_PUBLIC; 131 } 132 return CRYPT_OK; 133 LBL_ERR: 134 mp_clear_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL); 135 return err; 136 } 137 138 #endif /* MRSA */ 139 140 141 /* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_import.c,v $ */ 142 /* $Revision: 1.21 $ */ 143 /* $Date: 2006/12/04 22:23:27 $ */ 144