/** Encode a subject public key info @param out The output buffer @param outlen [in/out] Length of buffer and resulting length of output @param algorithm One out of the enum #public_key_algorithms @param public_key The buffer for the public key @param public_key_len The length of the public key buffer @param parameters_type The parameters' type out of the enum ltc_asn1_type @param parameters The parameters to include @param parameters_len The number of parameters to include @return CRYPT_OK on success */ int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen, unsigned int algorithm, void* public_key, unsigned long public_key_len, unsigned long parameters_type, void* parameters, unsigned long parameters_len) { int err; ltc_asn1_list alg_id[2]; oid_st oid; LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); err = pk_get_oid(algorithm, &oid); if (err != CRYPT_OK) { return err; } LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid.OID, oid.OIDlen); LTC_SET_ASN1(alg_id, 1, (ltc_asn1_type)parameters_type, parameters, parameters_len); return der_encode_sequence_multi(out, outlen, LTC_ASN1_SEQUENCE, (unsigned long)sizeof(alg_id)/sizeof(alg_id[0]), alg_id, LTC_ASN1_RAW_BIT_STRING, public_key_len*8U, public_key, LTC_ASN1_EOL, 0UL, NULL); }
/** Encode a SEQUENCE type using a VA list @param out [out] Destination for data @param outlen [in/out] Length of buffer and resulting length of output @remark <...> is of the form <type, size, data> (int, unsigned long, void*) @return CRYPT_OK on success */ int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, unsigned int algorithm, void* public_key, unsigned long* public_key_len, unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len) { int err, len; oid_st oid; unsigned char *tmpbuf; unsigned long tmpoid[16]; ltc_asn1_list alg_id[2]; ltc_asn1_list subject_pubkey[2]; LTC_ARGCHK(in != NULL); LTC_ARGCHK(inlen != 0); err = pk_get_oid(algorithm, &oid); if (err != CRYPT_OK) { return err; } /* see if the OpenSSL DER format RSA public key will work */ tmpbuf = XCALLOC(1, MAX_RSA_SIZE*8); if (tmpbuf == NULL) { err = CRYPT_MEM; goto LBL_ERR; } /* this includes the internal hash ID and optional params (NULL in this case) */ LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0])); LTC_SET_ASN1(alg_id, 1, parameters_type, parameters, parameters_len); /* the actual format of the SSL DER key is odd, it stores a RSAPublicKey in a **BIT** string ... so we have to extract it then proceed to convert bit to octet */ LTC_SET_ASN1(subject_pubkey, 0, LTC_ASN1_SEQUENCE, alg_id, 2); LTC_SET_ASN1(subject_pubkey, 1, LTC_ASN1_RAW_BIT_STRING, tmpbuf, MAX_RSA_SIZE*8); err=der_decode_sequence(in, inlen, subject_pubkey, 2UL); if (err != CRYPT_OK) { goto LBL_ERR; } len = subject_pubkey[1].size/8; if (*public_key_len > len) { memcpy(public_key, subject_pubkey[1].data, len); *public_key_len = len; } else { *public_key_len = len; err = CRYPT_BUFFER_OVERFLOW; goto LBL_ERR; } err = CRYPT_OK; LBL_ERR: XFREE(tmpbuf); return err; }
int ecc_export_full(unsigned char *out, unsigned long *outlen, int type, ecc_key *key) { int err; void *prime, *order, *a, *b, *gx, *gy; unsigned char bin_a[256], bin_b[256], bin_k[256], bin_g[512], bin_xy[512]; unsigned long len_a, len_b, len_k, len_g, len_xy; unsigned long cofactor, one = 1; oid_st oid; ltc_asn1_list seq_fieldid[2], seq_curve[2], seq_ecparams[6], seq_priv[4]; LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); if (key->type != PK_PRIVATE && type == PK_PRIVATE) return CRYPT_PK_TYPE_MISMATCH; if (ltc_ecc_is_valid_idx(key->idx) == 0) return CRYPT_INVALID_ARG; if ((err = mp_init_multi(&prime, &order, &a, &b, &gx, &gy, NULL)) != CRYPT_OK) return err; if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) goto error; if ((err = mp_read_radix(order, key->dp->order, 16)) != CRYPT_OK) goto error; if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) goto error; if ((err = mp_read_radix(a, key->dp->A, 16)) != CRYPT_OK) goto error; if ((err = mp_read_radix(gx, key->dp->Gx, 16)) != CRYPT_OK) goto error; if ((err = mp_read_radix(gy, key->dp->Gy, 16)) != CRYPT_OK) goto error; /* curve param a */ len_a = mp_unsigned_bin_size(a); if (len_a > sizeof(bin_a)) { err = CRYPT_BUFFER_OVERFLOW; goto error; } if ((err = mp_to_unsigned_bin(a, bin_a)) != CRYPT_OK) goto error; if (len_a == 0) { len_a = 1; bin_a[0] = 0; } /* XXX-TODO hack to handle case a == 0 */ /* curve param b */ len_b = mp_unsigned_bin_size(b); if (len_b > sizeof(bin_b)) { err = CRYPT_BUFFER_OVERFLOW; goto error; } if ((err = mp_to_unsigned_bin(b, bin_b)) != CRYPT_OK) goto error; if (len_b == 0) { len_b = 1; bin_b[0] = 0; } /* XXX-TODO hack to handle case b == 0 */ /* base point - we export uncompressed form */ len_g = sizeof(bin_g); if ((err = ecc_export_point(bin_g, &len_g, gx, gy, key->dp->size, 0)) != CRYPT_OK) goto error; /* public key */ len_xy = sizeof(bin_xy); if ((err = ecc_export_point(bin_xy, &len_xy, key->pubkey.x, key->pubkey.y, key->dp->size, 0)) != CRYPT_OK) goto error; /* co-factor */ cofactor = key->dp->cofactor; /* we support only prime-field EC */ if ((err = pk_get_oid(EC_PRIME_FIELD, &oid)) != CRYPT_OK) goto error; /* FieldID SEQUENCE */ LTC_SET_ASN1(seq_fieldid, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid.OID, oid.OIDlen); LTC_SET_ASN1(seq_fieldid, 1, LTC_ASN1_INTEGER, prime, 1UL); /* Curve SEQUENCE */ LTC_SET_ASN1(seq_curve, 0, LTC_ASN1_OCTET_STRING, bin_a, len_a); LTC_SET_ASN1(seq_curve, 1, LTC_ASN1_OCTET_STRING, bin_b, len_b); /* ECParameters SEQUENCE */ LTC_SET_ASN1(seq_ecparams, 0, LTC_ASN1_SHORT_INTEGER, &one, 1UL); LTC_SET_ASN1(seq_ecparams, 1, LTC_ASN1_SEQUENCE, seq_fieldid, 2UL); LTC_SET_ASN1(seq_ecparams, 2, LTC_ASN1_SEQUENCE, seq_curve, 2UL); LTC_SET_ASN1(seq_ecparams, 3, LTC_ASN1_OCTET_STRING, bin_g, len_g); LTC_SET_ASN1(seq_ecparams, 4, LTC_ASN1_INTEGER, order, 1UL); LTC_SET_ASN1(seq_ecparams, 5, LTC_ASN1_SHORT_INTEGER, &cofactor, 1UL); if (type == PK_PRIVATE) { /* private key format: http://tools.ietf.org/html/rfc5915 ECPrivateKey ::= SEQUENCE { # SEQUENCE version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), # INTEGER :01 privateKey OCTET STRING, # OCTET STRING [0] ECParameters ::= SEQUENCE { # SEQUENCE version INTEGER { ecpVer1(1) } (ecpVer1), # INTEGER :01 FieldID ::= SEQUENCE { # SEQUENCE fieldType FIELD-ID.&id({IOSet}), # OBJECT :prime-field parameters FIELD-ID.&Type({IOSet}{@fieldType}) # INTEGER } Curve ::= SEQUENCE { # SEQUENCE a FieldElement ::= OCTET STRING # OCTET STRING b FieldElement ::= OCTET STRING # OCTET STRING seed BIT STRING OPTIONAL } base ECPoint ::= OCTET STRING # OCTET STRING order INTEGER, # INTEGER cofactor INTEGER OPTIONAL # INTEGER } [1] publicKey # BIT STRING } */ /* private key */ len_k = mp_unsigned_bin_size(key->k); if (len_k > sizeof(bin_k)) { err = CRYPT_BUFFER_OVERFLOW; goto error; } if ((err = mp_to_unsigned_bin(key->k, bin_k)) != CRYPT_OK) goto error; LTC_SET_ASN1(seq_priv, 0, LTC_ASN1_SHORT_INTEGER, &one, 1UL); LTC_SET_ASN1(seq_priv, 1, LTC_ASN1_OCTET_STRING, bin_k, len_k); LTC_SET_ASN1(seq_priv, 2, LTC_ASN1_SEQUENCE, seq_ecparams, 6UL); LTC_SET_ASN1(seq_priv, 3, LTC_ASN1_RAW_BIT_STRING, bin_xy, 8*len_xy); seq_priv[2].tag = 0xA0; seq_priv[3].tag = 0xA1; err = der_encode_sequence(seq_priv, 4, out, outlen); } else { /* public key format: http://tools.ietf.org/html/rfc5480 SubjectPublicKeyInfo ::= SEQUENCE { # SEQUENCE AlgorithmIdentifier ::= SEQUENCE { # SEQUENCE algorithm OBJECT IDENTIFIER # OBJECT :id-ecPublicKey ECParameters ::= SEQUENCE { # SEQUENCE version INTEGER { ecpVer1(1) } (ecpVer1), # INTEGER :01 FieldID ::= SEQUENCE { # SEQUENCE fieldType FIELD-ID.&id({IOSet}), # OBJECT :prime-field parameters FIELD-ID.&Type({IOSet}{@fieldType}) # INTEGER } Curve ::= SEQUENCE { # SEQUENCE a FieldElement ::= OCTET STRING # OCTET STRING b FieldElement ::= OCTET STRING # OCTET STRING seed BIT STRING OPTIONAL } base ECPoint ::= OCTET STRING # OCTET STRING order INTEGER, # INTEGER cofactor INTEGER OPTIONAL # INTEGER } } subjectPublicKey BIT STRING # BIT STRING } */ err = der_encode_subject_public_key_info( out, outlen, PKA_EC, bin_xy, len_xy, LTC_ASN1_SEQUENCE, seq_ecparams, 6 ); } error: mp_clear_multi(prime, order, a, b, gx, gy, NULL); return err; }
/** Import an RSAPublicKey or RSAPrivateKey in PKCS#8 format @param in The packet to import from @param inlen It's length (octets) @param passwd The password for decrypting privkey (NOT SUPPORTED YET) @param passwdlen Password's length (octets) @param key [out] Destination for newly imported key @return CRYPT_OK if successful, upon error allocated memory is freed */ int rsa_import_pkcs8(const unsigned char *in, unsigned long inlen, const void *passwd, unsigned long passwdlen, rsa_key *key) { int err; void *zero, *iter; unsigned char *buf1 = NULL, *buf2 = NULL; unsigned long buf1len, buf2len; unsigned long oid[16]; oid_st rsaoid; ltc_asn1_list alg_seq[2], top_seq[3]; ltc_asn1_list alg_seq_e[2], key_seq_e[2], top_seq_e[2]; unsigned char *decrypted = NULL; unsigned long decryptedlen; LTC_ARGCHK(in != NULL); LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); /* get RSA alg oid */ err = pk_get_oid(PKA_RSA, &rsaoid); if (err != CRYPT_OK) { goto LBL_NOFREE; } /* alloc buffers */ buf1len = inlen; /* approx. */ buf1 = XMALLOC(buf1len); if (buf1 == NULL) { err = CRYPT_MEM; goto LBL_NOFREE; } buf2len = inlen; /* approx. */ buf2 = XMALLOC(buf2len); if (buf2 == NULL) { err = CRYPT_MEM; goto LBL_FREE1; } /* init key */ err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, &zero, &iter, NULL); if (err != CRYPT_OK) { goto LBL_FREE2; } /* try to decode encrypted priv key */ LTC_SET_ASN1(key_seq_e, 0, LTC_ASN1_OCTET_STRING, buf1, buf1len); LTC_SET_ASN1(key_seq_e, 1, LTC_ASN1_INTEGER, iter, 1UL); LTC_SET_ASN1(alg_seq_e, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, 16UL); LTC_SET_ASN1(alg_seq_e, 1, LTC_ASN1_SEQUENCE, key_seq_e, 2UL); LTC_SET_ASN1(top_seq_e, 0, LTC_ASN1_SEQUENCE, alg_seq_e, 2UL); LTC_SET_ASN1(top_seq_e, 1, LTC_ASN1_OCTET_STRING, buf2, buf2len); err=der_decode_sequence(in, inlen, top_seq_e, 2UL); if (err == CRYPT_OK) { LTC_UNUSED_PARAM(passwd); LTC_UNUSED_PARAM(passwdlen); /* XXX: TODO encrypted pkcs8 not implemented yet */ /* fprintf(stderr, "decrypt: iter=%ld salt.len=%ld encdata.len=%ld\n", mp_get_int(iter), key_seq_e[0].size, top_seq_e[1].size); */ err = CRYPT_PK_INVALID_TYPE; goto LBL_ERR; } else { decrypted = (unsigned char *)in; decryptedlen = inlen; } /* try to decode unencrypted priv key */ LTC_SET_ASN1(alg_seq, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, 16UL); LTC_SET_ASN1(alg_seq, 1, LTC_ASN1_NULL, NULL, 0UL); LTC_SET_ASN1(top_seq, 0, LTC_ASN1_INTEGER, zero, 1UL); LTC_SET_ASN1(top_seq, 1, LTC_ASN1_SEQUENCE, alg_seq, 2UL); LTC_SET_ASN1(top_seq, 2, LTC_ASN1_OCTET_STRING, buf1, buf1len); err=der_decode_sequence(decrypted, decryptedlen, top_seq, 3UL); if (err != CRYPT_OK) { goto LBL_ERR; } /* check alg oid */ if ((alg_seq[0].size != rsaoid.OIDlen) || XMEMCMP(rsaoid.OID, alg_seq[0].data, rsaoid.OIDlen * sizeof(rsaoid.OID[0])) != 0) { err = CRYPT_PK_INVALID_TYPE; goto LBL_ERR; } err = der_decode_sequence_multi(buf1, top_seq[2].size, LTC_ASN1_INTEGER, 1UL, zero, LTC_ASN1_INTEGER, 1UL, key->N, LTC_ASN1_INTEGER, 1UL, key->e, LTC_ASN1_INTEGER, 1UL, key->d, LTC_ASN1_INTEGER, 1UL, key->p, LTC_ASN1_INTEGER, 1UL, key->q, LTC_ASN1_INTEGER, 1UL, key->dP, LTC_ASN1_INTEGER, 1UL, key->dQ, LTC_ASN1_INTEGER, 1UL, key->qP, LTC_ASN1_EOL, 0UL, NULL); if (err != CRYPT_OK) { goto LBL_ERR; } key->type = PK_PRIVATE; err = CRYPT_OK; goto LBL_FREE2; LBL_ERR: rsa_free(key); LBL_FREE2: mp_clear_multi(iter, zero, NULL); XFREE(buf2); LBL_FREE1: XFREE(buf1); LBL_NOFREE: return err; }