/* * Copyright (C) 2003-2012 Free Software Foundation, Inc. * * Author: Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ #include "gnutls_int.h" #include "errors.h" #include #include #include #include "common.h" #include "x509_int.h" #include /* Reads an Integer from the DER encoded data */ int _gnutls_x509_read_der_int(uint8_t * der, int dersize, bigint_t * out) { int result; ASN1_TYPE spk = ASN1_TYPE_EMPTY; /* == INTEGER */ if ((result = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.DSAPublicKey", &spk)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = _asn1_strict_der_decode(&spk, der, dersize, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&spk); return _gnutls_asn2err(result); } /* Read Y */ if ((result = _gnutls_x509_read_int(spk, "", out)) < 0) { gnutls_assert(); asn1_delete_structure(&spk); return _gnutls_asn2err(result); } asn1_delete_structure(&spk); return 0; } /* Extracts DSA and RSA parameters from a certificate. */ int _gnutls_get_asn_mpis(ASN1_TYPE asn, const char *root, gnutls_pk_params_st * params) { int result; char name[256]; gnutls_datum_t tmp = { NULL, 0 }; gnutls_pk_algorithm_t pk_algorithm; gnutls_pk_params_init(params); result = _gnutls_x509_get_pk_algorithm(asn, root, NULL); if (result < 0) { gnutls_assert(); return result; } pk_algorithm = result; /* Read the algorithm's parameters */ _asnstr_append_name(name, sizeof(name), root, ".subjectPublicKey"); result = _gnutls_x509_read_value(asn, name, &tmp); if (result < 0) { gnutls_assert(); return result; } if ((result = _gnutls_x509_read_pubkey(pk_algorithm, tmp.data, tmp.size, params)) < 0) { gnutls_assert(); goto error; } /* Now read the parameters */ _gnutls_free_datum(&tmp); _asnstr_append_name(name, sizeof(name), root, ".algorithm.parameters"); /* FIXME: If the parameters are not included in the certificate * then the issuer's parameters should be used. This is not * done yet. */ if (pk_algorithm != GNUTLS_PK_RSA) { /* RSA doesn't use parameters */ result = _gnutls_x509_read_value(asn, name, &tmp); if (result < 0) { gnutls_assert(); goto error; } result = _gnutls_x509_read_pubkey_params(pk_algorithm, tmp.data, tmp.size, params); if (result < 0) { gnutls_assert(); goto error; } } result = 0; error: if (result < 0) gnutls_pk_params_release(params); _gnutls_free_datum(&tmp); return result; } /* Extracts DSA and RSA parameters from a certificate. */ int _gnutls_x509_crt_get_mpis(gnutls_x509_crt_t cert, gnutls_pk_params_st * params) { /* Read the algorithm's OID */ return _gnutls_get_asn_mpis(cert->cert, "tbsCertificate.subjectPublicKeyInfo", params); } /* Extracts DSA and RSA parameters from a certificate. */ int _gnutls_x509_crq_get_mpis(gnutls_x509_crq_t cert, gnutls_pk_params_st * params) { /* Read the algorithm's OID */ return _gnutls_get_asn_mpis(cert->crq, "certificationRequestInfo.subjectPKInfo", params); } /* * This function writes and encodes the parameters for DSS or RSA keys. * This is the "signatureAlgorithm" fields. * * If @legacy is non-zero then the legacy value for PKCS#7 signatures * will be written for RSA signatures. */ int _gnutls_x509_write_sig_params(ASN1_TYPE dst, const char *dst_name, gnutls_pk_algorithm_t pk_algorithm, gnutls_digest_algorithm_t dig, unsigned legacy) { int result; char name[128]; const char *oid; _gnutls_str_cpy(name, sizeof(name), dst_name); _gnutls_str_cat(name, sizeof(name), ".algorithm"); if (legacy && pk_algorithm == GNUTLS_PK_RSA) oid = PK_PKIX1_RSA_OID; else oid = gnutls_sign_get_oid(gnutls_pk_to_sign(pk_algorithm, dig)); if (oid == NULL) { gnutls_assert(); _gnutls_debug_log ("Cannot find OID for sign algorithm pk: %d dig: %d\n", (int) pk_algorithm, (int) dig); return GNUTLS_E_INVALID_REQUEST; } /* write the OID. */ result = asn1_write_value(dst, name, oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } _gnutls_str_cpy(name, sizeof(name), dst_name); _gnutls_str_cat(name, sizeof(name), ".parameters"); if (pk_algorithm == GNUTLS_PK_RSA) result = asn1_write_value(dst, name, ASN1_NULL, ASN1_NULL_SIZE); else result = asn1_write_value(dst, name, NULL, 0); if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) { /* Here we ignore the element not found error, since this * may have been disabled before. */ gnutls_assert(); return _gnutls_asn2err(result); } return 0; } /* this function reads a (small) unsigned integer * from asn1 structs. Combines the read and the convertion * steps. */ int _gnutls_x509_read_uint(ASN1_TYPE node, const char *value, unsigned int *ret) { int len, result; uint8_t *tmpstr; len = 0; result = asn1_read_value(node, value, NULL, &len); if (result != ASN1_MEM_ERROR) { gnutls_assert(); return _gnutls_asn2err(result); } tmpstr = gnutls_malloc(len); if (tmpstr == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } result = asn1_read_value(node, value, tmpstr, &len); if (result != ASN1_SUCCESS) { gnutls_assert(); gnutls_free(tmpstr); return _gnutls_asn2err(result); } if (len == 1) *ret = tmpstr[0]; else if (len == 2) *ret = _gnutls_read_uint16(tmpstr); else if (len == 3) *ret = _gnutls_read_uint24(tmpstr); else if (len == 4) *ret = _gnutls_read_uint32(tmpstr); else { gnutls_assert(); gnutls_free(tmpstr); return GNUTLS_E_INTERNAL_ERROR; } gnutls_free(tmpstr); return 0; } /* Writes the specified integer into the specified node. */ int _gnutls_x509_write_uint32(ASN1_TYPE node, const char *value, uint32_t num) { uint8_t tmpstr[4]; int result; _gnutls_write_uint32(num, tmpstr); result = asn1_write_value(node, value, tmpstr, 4); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } return 0; }