diff options
Diffstat (limited to 'src/gcrypt/asn1.c')
-rw-r--r-- | src/gcrypt/asn1.c | 602 |
1 files changed, 602 insertions, 0 deletions
diff --git a/src/gcrypt/asn1.c b/src/gcrypt/asn1.c new file mode 100644 index 00000000..b1388420 --- /dev/null +++ b/src/gcrypt/asn1.c @@ -0,0 +1,602 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <gcrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/errors.h> + +#include <xmlsec/gcrypt/crypto.h> + +#include "asn1.h" + +/************************************************************************** + * + * ASN.1 parser is taken from GCrypt tests + * + *************************************************************************/ + +/* ASN.1 classes. */ +enum +{ + UNIVERSAL = 0, + APPLICATION = 1, + ASNCONTEXT = 2, + PRIVATE = 3 +}; + + +/* ASN.1 tags. */ +enum +{ + TAG_NONE = 0, + TAG_BOOLEAN = 1, + TAG_INTEGER = 2, + TAG_BIT_STRING = 3, + TAG_OCTET_STRING = 4, + TAG_NULL = 5, + TAG_OBJECT_ID = 6, + TAG_OBJECT_DESCRIPTOR = 7, + TAG_EXTERNAL = 8, + TAG_REAL = 9, + TAG_ENUMERATED = 10, + TAG_EMBEDDED_PDV = 11, + TAG_UTF8_STRING = 12, + TAG_REALTIVE_OID = 13, + TAG_SEQUENCE = 16, + TAG_SET = 17, + TAG_NUMERIC_STRING = 18, + TAG_PRINTABLE_STRING = 19, + TAG_TELETEX_STRING = 20, + TAG_VIDEOTEX_STRING = 21, + TAG_IA5_STRING = 22, + TAG_UTC_TIME = 23, + TAG_GENERALIZED_TIME = 24, + TAG_GRAPHIC_STRING = 25, + TAG_VISIBLE_STRING = 26, + TAG_GENERAL_STRING = 27, + TAG_UNIVERSAL_STRING = 28, + TAG_CHARACTER_STRING = 29, + TAG_BMP_STRING = 30 +}; + +/* ASN.1 Parser object. */ +struct tag_info +{ + int class; /* Object class. */ + unsigned long tag; /* The tag of the object. */ + unsigned long length; /* Length of the values. */ + int nhdr; /* Length of the header (TL). */ + unsigned int ndef:1; /* The object has an indefinite length. */ + unsigned int cons:1; /* This is a constructed object. */ +}; + +/* Parse the buffer at the address BUFFER which consists of the number + of octets as stored at BUFLEN. Return the tag and the length part + from the TLV triplet. Update BUFFER and BUFLEN on success. Checks + that the encoded length does not exhaust the length of the provided + buffer. */ +static int +xmlSecGCryptAsn1ParseTag (xmlSecByte const **buffer, xmlSecSize *buflen, struct tag_info *ti) +{ + int c; + unsigned long tag; + const xmlSecByte *buf; + xmlSecSize length; + + xmlSecAssert2(buffer != NULL, -1); + xmlSecAssert2((*buffer) != NULL, -1); + xmlSecAssert2(buflen != NULL, -1); + xmlSecAssert2(ti != NULL, -1); + + /* initialize */ + buf = *buffer; + length = *buflen; + + ti->length = 0; + ti->ndef = 0; + ti->nhdr = 0; + + /* Get the tag */ + if (length <= 0) { + return(-1); /* Premature EOF. */ + } + c = *buf++; + length--; + ti->nhdr++; + + ti->class = (c & 0xc0) >> 6; + ti->cons = !!(c & 0x20); + tag = (c & 0x1f); + + if (tag == 0x1f) { + tag = 0; + do { + tag <<= 7; + if (length <= 0) { + return(-1); /* Premature EOF. */ + } + c = *buf++; + length--; + ti->nhdr++; + tag |= (c & 0x7f); + } while ( (c & 0x80) ); + } + ti->tag = tag; + + /* Get the length */ + if(length <= 0) { + return -1; /* Premature EOF. */ + } + c = *buf++; + length--; + ti->nhdr++; + + if ( !(c & 0x80) ) { + ti->length = c; + } else if (c == 0x80) { + ti->ndef = 1; + } else if (c == 0xff) { + return -1; /* Forbidden length value. */ + } else { + xmlSecSize len = 0; + int count = c & 0x7f; + + for (; count; count--) { + len <<= 8; + if (length <= 0) { + return -1; /* Premature EOF. */ + } + c = *buf++; length--; + ti->nhdr++; + len |= (c & 0xff); + } + ti->length = len; + } + + if (ti->class == UNIVERSAL && !ti->tag) { + ti->length = 0; + } + + if (ti->length > length) { + return(-1); /* Data larger than buffer. */ + } + + /* done */ + *buffer = buf; + *buflen = length; + return(0); +} + +static int +xmlSecGCryptAsn1ParseIntegerSequence(xmlSecByte const **buffer, xmlSecSize *buflen, + gcry_mpi_t * params, int params_size) { + const xmlSecByte *buf; + xmlSecSize length; + struct tag_info ti; + gcry_error_t err; + int idx = 0; + int ret; + + xmlSecAssert2(buffer != NULL, -1); + xmlSecAssert2((*buffer) != NULL, -1); + xmlSecAssert2(buflen != NULL, -1); + xmlSecAssert2(params != NULL, -1); + xmlSecAssert2(params_size > 0, -1); + + /* initialize */ + buf = *buffer; + length = *buflen; + + /* read SEQUENCE */ + memset(&ti, 0, sizeof(ti)); + ret = xmlSecGCryptAsn1ParseTag (&buf, &length, &ti); + if((ret != 0) || (ti.tag != TAG_SEQUENCE) || ti.class || !ti.cons || ti.ndef) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGCryptAsn1ParseTag", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "TAG_SEQUENCE is expected: tag=%d", + (int)ti.tag); + return(-1); + } + + /* read INTEGERs */ + for (idx = 0; ((idx < params_size) && (length > 0)); idx++) { + memset(&ti, 0, sizeof(ti)); + ret = xmlSecGCryptAsn1ParseTag (&buf, &length, &ti); + if((ret != 0) || (ti.tag != TAG_INTEGER) || ti.class || ti.cons || ti.ndef) + { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGCryptAsn1ParseTag", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "TAG_INTEGER is expected - index=%d, tag=%d", + (int)idx, (int)ti.tag); + return(-1); + } + + err = gcry_mpi_scan(&(params[idx]), GCRYMPI_FMT_USG, buf, ti.length, NULL); + if((err != GPG_ERR_NO_ERROR) || (params[idx] == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "gcry_mpi_scan", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_GCRYPT_REPORT_ERROR(err)); + return(-1); + } + buf += ti.length; + length -= ti.length; + } + + /* did we parse everything? */ + if(length > 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGCryptAsn1ParseTag", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "too many params - cur=%d, expected=%d", + (int)(idx - 1), (int)params_size); + return(-1); + } + + /* done */ + *buffer = buf; + *buflen = length; + return(idx); +} + +xmlSecKeyDataPtr +xmlSecGCryptParseDer(const xmlSecByte * der, xmlSecSize derlen, + enum xmlSecGCryptDerKeyType type) { + xmlSecKeyDataPtr key_data = NULL; + gcry_sexp_t s_pub_key = NULL; + gcry_sexp_t s_priv_key = NULL; + gcry_error_t err; + gcry_mpi_t keyparms[20]; + int keyparms_num; + unsigned int idx; + int ret; + + xmlSecAssert2(der != NULL, NULL); + xmlSecAssert2(derlen > 0, NULL); + + /* Parse the ASN.1 structure. */ + memset(&keyparms, 0, sizeof(keyparms)); + ret = xmlSecGCryptAsn1ParseIntegerSequence( + &der, &derlen, + keyparms, sizeof(keyparms) / sizeof(keyparms[0]) + ); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGCryptAsn1ParseIntegerSequence", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + keyparms_num = ret; + + /* The value of the first integer should be 0. */ + if ((keyparms_num < 1) || (gcry_mpi_cmp_ui(keyparms[0], 0) != 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGCryptAsn1ParseTag", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "num=%d", + (int)keyparms_num); + goto done; + } + + /* do we need to guess the key type? not robust but the best we can do */ + if(type == xmlSecGCryptDerKeyTypeAuto) { + switch(keyparms_num) { + case 3: + /* Public RSA */ + type = xmlSecGCryptDerKeyTypePublicRsa; + case 5: + /* Public DSA */ + type = xmlSecGCryptDerKeyTypePublicDsa; + case 6: + /* Private DSA */ + type = xmlSecGCryptDerKeyTypePrivateDsa; + break; + case 9: + /* Private RSA */ + type = xmlSecGCryptDerKeyTypePrivateRsa; + break; + default: + /* unknown */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "Unexpected number of parameters, unknown key type", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "keyparms_num=%d", (int)keyparms_num); + goto done; + } + } + + + switch(type) { +#ifndef XMLSEC_NO_DSA + case xmlSecGCryptDerKeyTypePrivateDsa: + /* check we have enough params */ + if(keyparms_num != 6) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "Private DSA key: 6 parameters exepcted", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "parms_num=%d", (int)keyparms_num); + goto done; + } + + /* Convert from OpenSSL parameter ordering to the OpenPGP order. */ + /* First check that x < y; if not swap x and y */ + if (gcry_mpi_cmp (keyparms[4], keyparms[5]) > 0) { + gcry_mpi_swap (keyparms[4], keyparms[5]); + } + + /* Build the S-expressions */ + err = gcry_sexp_build (&s_priv_key, NULL, + "(private-key(dsa(p%m)(q%m)(g%m)(x%m)(y%m)))", + keyparms[1], keyparms[2], keyparms[3], keyparms[4], keyparms[5] + ); + if((err != GPG_ERR_NO_ERROR) || (s_priv_key == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "gcry_sexp_build(private-key/dsa)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_GCRYPT_REPORT_ERROR(err)); + goto done; + } + + err = gcry_sexp_build (&s_pub_key, NULL, + "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", + keyparms[1], keyparms[2], keyparms[3], keyparms[5] + ); + if((err != GPG_ERR_NO_ERROR) || (s_pub_key == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "gcry_sexp_build(public-key/dsa)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_GCRYPT_REPORT_ERROR(err)); + goto done; + } + + /* construct key and key data */ + key_data = xmlSecKeyDataCreate(xmlSecGCryptKeyDataDsaId); + if(key_data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecGCryptKeyDataDsaId"); + goto done; + } + + ret = xmlSecGCryptKeyDataDsaAdoptKeyPair(key_data, s_pub_key, s_priv_key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGCryptKeyDataDsaAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecGCryptKeyDataDsaId"); + xmlSecKeyDataDestroy(key_data); + key_data = NULL; + goto done; + } + s_pub_key = NULL; /* owned by key_data now */ + s_priv_key = NULL; /* owned by key_data now */ + break; + + case xmlSecGCryptDerKeyTypePublicDsa: + /* check we have enough params */ + if(keyparms_num != 5) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "Public DSA key: 5 parameters exepcted", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "parms_num=%d", (int)keyparms_num); + goto done; + } + + /* Build the S-expression. */ + err = gcry_sexp_build (&s_pub_key, NULL, + "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", + keyparms[2], keyparms[3], keyparms[4], keyparms[1] + ); + if((err != GPG_ERR_NO_ERROR) || (s_pub_key == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "gcry_sexp_build(public-key/dsa)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_GCRYPT_REPORT_ERROR(err)); + goto done; + } + + /* construct key and key data */ + key_data = xmlSecKeyDataCreate(xmlSecGCryptKeyDataDsaId); + if(key_data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecGCryptKeyDataDsaId"); + goto done; + } + + ret = xmlSecGCryptKeyDataDsaAdoptKeyPair(key_data, s_pub_key, NULL); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGCryptKeyDataDsaAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecGCryptKeyDataDsaId"); + xmlSecKeyDataDestroy(key_data); + key_data = NULL; + goto done; + } + s_pub_key = NULL; /* owned by key_data now */ + break; +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA + case xmlSecGCryptDerKeyTypePrivateRsa: + /* check we have enough params */ + if(keyparms_num != 9) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "Private RSA key: 9 parameters exepcted", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "parms_num=%d", (int)keyparms_num); + goto done; + } + + /* Convert from OpenSSL parameter ordering to the OpenPGP order. */ + /* First check that p < q; if not swap p and q and recompute u. */ + if (gcry_mpi_cmp (keyparms[4], keyparms[5]) > 0) { + gcry_mpi_swap (keyparms[4], keyparms[5]); + gcry_mpi_invm (keyparms[8], keyparms[4], keyparms[5]); + } + + /* Build the S-expression. */ + err = gcry_sexp_build (&s_priv_key, NULL, + "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", + keyparms[1], keyparms[2], + keyparms[3], keyparms[4], + keyparms[5], keyparms[8] + ); + if((err != GPG_ERR_NO_ERROR) || (s_priv_key == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "gcry_sexp_build(private-key/rsa)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_GCRYPT_REPORT_ERROR(err)); + goto done; + } + + err = gcry_sexp_build (&s_pub_key, NULL, + "(public-key(rsa(n%m)(e%m)))", + keyparms[1], keyparms[2] + ); + if((err != GPG_ERR_NO_ERROR) || (s_pub_key == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "gcry_sexp_build(public-key/rsa)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_GCRYPT_REPORT_ERROR(err)); + goto done; + } + + /* construct key and key data */ + key_data = xmlSecKeyDataCreate(xmlSecGCryptKeyDataRsaId); + if(key_data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecGCryptKeyDataRsaId"); + goto done; + } + + ret = xmlSecGCryptKeyDataRsaAdoptKeyPair(key_data, s_pub_key, s_priv_key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGCryptKeyDataRsaAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecGCryptKeyDataRsaId"); + xmlSecKeyDataDestroy(key_data); + key_data = NULL; + goto done; + } + s_pub_key = NULL; /* owned by key_data now */ + s_priv_key = NULL; /* owned by key_data now */ + break; + + case xmlSecGCryptDerKeyTypePublicRsa: + /* check we have enough params */ + if(keyparms_num != 3) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "Public RSA key: 3 parameters exepcted", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "parms_num=%d", (int)keyparms_num); + goto done; + } + + /* Build the S-expression. */ + err = gcry_sexp_build (&s_pub_key, NULL, + "(public-key(rsa(n%m)(e%m)))", + keyparms[1], keyparms[2] + ); + if((err != GPG_ERR_NO_ERROR) || (s_pub_key == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "gcry_sexp_build(public-key/rsa)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_GCRYPT_REPORT_ERROR(err)); + goto done; + } + + /* construct key and key data */ + key_data = xmlSecKeyDataCreate(xmlSecGCryptKeyDataRsaId); + if(key_data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecGCryptKeyDataRsaId"); + goto done; + } + + ret = xmlSecGCryptKeyDataRsaAdoptKeyPair(key_data, s_pub_key, NULL); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGCryptKeyDataRsaAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecGCryptKeyDataRsaId"); + xmlSecKeyDataDestroy(key_data); + key_data = NULL; + goto done; + } + s_pub_key = NULL; /* owned by key_data now */ + break; +#endif /* XMLSEC_NO_RSA */ + + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "Unsupported key type", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "type=%d", (int)type); + goto done; + break; + } + +done: + if(s_priv_key != NULL) { + gcry_sexp_release(s_priv_key); + } + if(s_pub_key != NULL) { + gcry_sexp_release(s_pub_key); + } + for (idx = 0; idx < sizeof(keyparms) / sizeof(keyparms[0]); idx++) { + if(keyparms[idx] != NULL) { + gcry_mpi_release (keyparms[idx]); + } + } + + return(key_data); +} |