Home | History | Annotate | Download | only in rsa
      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