/* * some x509 certificate functions that relate to MPI parameter * setting. This writes the BIT STRING subjectPublicKey. * Needs 2 parameters (m,e). * * Allocates the space used to store the DER data. */ int _gnutls_x509_write_rsa_params (bigint_t * params, int params_size, gnutls_datum_t * der) { int result; ASN1_TYPE spk = ASN1_TYPE_EMPTY; der->data = NULL; der->size = 0; if (params_size < 2) { gnutls_assert (); result = GNUTLS_E_INVALID_REQUEST; goto cleanup; } if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), "GNUTLS.RSAPublicKey", &spk)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = _gnutls_x509_write_int (spk, "modulus", params[0], 1); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_write_int (spk, "publicExponent", params[1], 1); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_der_encode (spk, "", der, 0); if (result < 0) { gnutls_assert (); goto cleanup; } asn1_delete_structure (&spk); return 0; cleanup: asn1_delete_structure (&spk); return result; }
/* Convert the given name to GeneralNames in a DER encoded extension. * This is the same as subject alternative name. */ int _gnutls_x509_ext_gen_subject_alt_name (gnutls_x509_subject_alt_name_t type, const void *data, unsigned int data_size, gnutls_datum_t * prev_der_ext, gnutls_datum_t * der_ext) { ASN1_TYPE ext = ASN1_TYPE_EMPTY; int result; result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.GeneralNames", &ext); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } if (prev_der_ext != NULL && prev_der_ext->data != NULL && prev_der_ext->size != 0) { result = asn1_der_decoding (&ext, prev_der_ext->data, prev_der_ext->size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&ext); return _gnutls_asn2err (result); } } result = write_new_general_name (ext, "", type, data, data_size); if (result < 0) { gnutls_assert (); asn1_delete_structure (&ext); return result; } result = _gnutls_x509_der_encode (ext, "", der_ext, 0); asn1_delete_structure (&ext); if (result < 0) { gnutls_assert (); return result; } return 0; }
/* * This function writes the parameters for DSS keys. * Needs 3 parameters (p,q,g). * * Allocates the space used to store the DER data. */ static int _gnutls_x509_write_dsa_params(gnutls_pk_params_st * params, gnutls_datum_t * der) { int result; ASN1_TYPE spk = ASN1_TYPE_EMPTY; der->data = NULL; der->size = 0; if (params->params_nr < DSA_PUBLIC_PARAMS - 1) { gnutls_assert(); result = GNUTLS_E_INVALID_REQUEST; goto cleanup; } if ((result = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.DSAParameters", &spk)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = _gnutls_x509_write_int(spk, "p", params->params[0], 1); if (result < 0) { gnutls_assert(); goto cleanup; } result = _gnutls_x509_write_int(spk, "q", params->params[1], 1); if (result < 0) { gnutls_assert(); goto cleanup; } result = _gnutls_x509_write_int(spk, "g", params->params[2], 1); if (result < 0) { gnutls_assert(); goto cleanup; } result = _gnutls_x509_der_encode(spk, "", der, 0); if (result < 0) { gnutls_assert(); goto cleanup; } result = 0; cleanup: asn1_delete_structure(&spk); return result; }
/** * gnutls_x509_crt_set_private_key_usage_period: * @crt: a certificate of type #gnutls_x509_crt_t * @activation: The activation time * @expiration: The expiration time * * This function will set the private key usage period extension (2.5.29.16). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_crt_set_private_key_usage_period(gnutls_x509_crt_t crt, time_t activation, time_t expiration) { int result; gnutls_datum_t der_data; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; if (crt == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.PrivateKeyUsagePeriod", &c2); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = _gnutls_x509_set_time(c2, "notBefore", activation, 1); if (result < 0) { gnutls_assert(); goto cleanup; } result = _gnutls_x509_set_time(c2, "notAfter", expiration, 1); if (result < 0) { gnutls_assert(); goto cleanup; } result = _gnutls_x509_der_encode(c2, "", &der_data, 0); if (result < 0) { gnutls_assert(); goto cleanup; } result = _gnutls_x509_crt_set_extension(crt, "2.5.29.16", &der_data, 0); _gnutls_free_datum(&der_data); crt->use_extensions = 1; cleanup: asn1_delete_structure(&c2); return result; }
static int encode_user_notice(const gnutls_datum_t * txt, gnutls_datum_t * der_data) { int result; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; if ((result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.UserNotice", &c2)) != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto error; } /* delete noticeRef */ result = asn1_write_value(c2, "noticeRef", NULL, 0); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto error; } result = asn1_write_value(c2, "explicitText", "utf8String", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto error; } result = asn1_write_value(c2, "explicitText.utf8String", txt->data, txt->size); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto error; } result = _gnutls_x509_der_encode(c2, "", der_data, 0); if (result < 0) { gnutls_assert(); goto error; } result = 0; error: asn1_delete_structure(&c2); return result; }
/* * This function writes the parameters for ECC keys. * That is the ECParameters struct. * * Allocates the space used to store the DER data. */ int _gnutls_x509_write_ecc_params(gnutls_ecc_curve_t curve, gnutls_datum_t * der) { int result; ASN1_TYPE spk = ASN1_TYPE_EMPTY; const char *oid; der->data = NULL; der->size = 0; oid = _gnutls_ecc_curve_get_oid(curve); if (oid == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if ((result = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.ECParameters", &spk)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } if ((result = asn1_write_value(spk, "", "namedCurve", 1)) != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if ((result = asn1_write_value(spk, "namedCurve", oid, 1)) != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } result = _gnutls_x509_der_encode(spk, "", der, 0); if (result < 0) { gnutls_assert(); goto cleanup; } result = 0; cleanup: asn1_delete_structure(&spk); return result; }
/* Reads the DER signed data from the certificate and allocates space and * returns them into signed_data. */ int _gnutls_x509_get_signed_data(ASN1_TYPE src, const gnutls_datum *_der, const char *src_name, gnutls_datum_t * signed_data) { int start, end, result; gnutls_datum_t der; unsigned need_free = 0; if (_der == NULL || _der->size == 0) { result = _gnutls_x509_der_encode(src, "", &der, 0); if (result < 0) { gnutls_assert(); return result; } need_free = 1; } else { der.data = _der->data; der.size = _der->size; } /* Get the signed data */ result = asn1_der_decoding_startEnd(src, der.data, der.size, src_name, &start, &end); if (result != ASN1_SUCCESS) { result = _gnutls_asn2err(result); gnutls_assert(); goto cleanup; } result = _gnutls_set_datum(signed_data, &der.data[start], end - start + 1); if (result < 0) { gnutls_assert(); goto cleanup; } result = 0; cleanup: if (need_free != 0) _gnutls_free_datum(&der); return result; }
/* encodes the Dss-Sig-Value structure */ static int encode_ber_rs (gnutls_datum_t * sig_value, mpi_t r, mpi_t s) { ASN1_TYPE sig; int result, tot_len; if ((result = asn1_create_element (_gnutls_get_gnutls_asn (), "GNUTLS.DSASignatureValue", &sig)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = _gnutls_x509_write_int (sig, "r", r, 1); if (result < 0) { gnutls_assert (); asn1_delete_structure (&sig); return result; } result = _gnutls_x509_write_int (sig, "s", s, 1); if (result < 0) { gnutls_assert (); asn1_delete_structure (&sig); return result; } tot_len = 0; result = _gnutls_x509_der_encode (sig, "", sig_value, 0); asn1_delete_structure (&sig); if (result < 0) { gnutls_assert (); return result; } return 0; }
/* Reads the DER signed data from the certificate and allocates space and * returns them into signed_data. */ int _gnutls_x509_get_signed_data (ASN1_TYPE src, const char *src_name, gnutls_datum_t * signed_data) { gnutls_datum_t der; int start, end, result; result = _gnutls_x509_der_encode (src, "", &der, 0); if (result < 0) { gnutls_assert (); return result; } /* Get the signed data */ result = asn1_der_decoding_startEnd (src, der.data, der.size, src_name, &start, &end); if (result != ASN1_SUCCESS) { result = _gnutls_asn2err (result); gnutls_assert (); goto cleanup; } result = _gnutls_set_datum (signed_data, &der.data[start], end - start + 1); if (result < 0) { gnutls_assert (); goto cleanup; } result = 0; cleanup: _gnutls_free_datum (&der); return result; }
/* generate the AuthorityKeyID in a DER encoded extension */ int _gnutls_x509_ext_gen_auth_key_id (const void *id, size_t id_size, gnutls_datum_t * der_ext) { ASN1_TYPE ext = ASN1_TYPE_EMPTY; int result; result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.AuthorityKeyIdentifier", &ext); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = asn1_write_value (ext, "keyIdentifier", id, id_size); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&ext); return _gnutls_asn2err (result); } asn1_write_value (ext, "authorityCertIssuer", NULL, 0); asn1_write_value (ext, "authorityCertSerialNumber", NULL, 0); result = _gnutls_x509_der_encode (ext, "", der_ext, 0); asn1_delete_structure (&ext); if (result < 0) { gnutls_assert (); return result; } return 0; }
/* encodes the Dss-Sig-Value structure */ int _gnutls_encode_ber_rs_raw(gnutls_datum_t * sig_value, const gnutls_datum_t * r, const gnutls_datum_t * s) { ASN1_TYPE sig; int result; if ((result = asn1_create_element(_gnutls_get_gnutls_asn(), "GNUTLS.DSASignatureValue", &sig)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = asn1_write_value(sig, "r", r->data, r->size); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&sig); return _gnutls_asn2err(result); } result = asn1_write_value(sig, "s", s->data, s->size); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&sig); return _gnutls_asn2err(result); } result = _gnutls_x509_der_encode(sig, "", sig_value, 0); asn1_delete_structure(&sig); if (result < 0) return gnutls_assert_val(result); return 0; }
/* generate the keyUsage in a DER encoded extension * Use an ORed SEQUENCE of GNUTLS_KEY_* for usage. */ int _gnutls_x509_ext_gen_keyUsage (uint16_t usage, gnutls_datum_t * der_ext) { ASN1_TYPE ext = ASN1_TYPE_EMPTY; int result; uint8_t str[2]; result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.KeyUsage", &ext); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } str[0] = usage & 0xff; str[1] = usage >> 8; result = asn1_write_value (ext, "", str, 9); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&ext); return _gnutls_asn2err (result); } result = _gnutls_x509_der_encode (ext, "", der_ext, 0); asn1_delete_structure (&ext); if (result < 0) { gnutls_assert (); return result; } return 0; }
/* generate an INTEGER in a DER encoded extension */ int _gnutls_x509_ext_gen_number (const uint8_t * number, size_t nr_size, gnutls_datum_t * der_ext) { ASN1_TYPE ext = ASN1_TYPE_EMPTY; int result; result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.CertificateSerialNumber", &ext); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = asn1_write_value (ext, "", number, nr_size); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&ext); return _gnutls_asn2err (result); } result = _gnutls_x509_der_encode (ext, "", der_ext, 0); asn1_delete_structure (&ext); if (result < 0) { gnutls_assert (); return result; } return 0; }
/** * gnutls_pkcs12_bag_set_crl: * @bag: The bag * @crl: the CRL to be copied. * * This function will insert the given CRL into the * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data(). * * Returns: the index of the added bag on success, or a negative error code * on failure. **/ int gnutls_pkcs12_bag_set_crl(gnutls_pkcs12_bag_t bag, gnutls_x509_crl_t crl) { int ret; gnutls_datum_t data; if (bag == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_x509_der_encode(crl->crl, "", &data, 0); if (ret < 0) { gnutls_assert(); return ret; } ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_CRL, &data); _gnutls_free_datum(&data); return ret; }
/** * gnutls_dh_params_export2_pkcs3: * @params: Holds the DH parameters * @format: the format of output params. One of PEM or DER. * @out: will contain a PKCS3 DHParams structure PEM or DER encoded * * This function will export the given dh parameters to a PKCS3 * DHParams structure. This is the format generated by "openssl dhparam" tool. * The data in @out will be allocated using gnutls_malloc(). * * If the structure is PEM encoded, it will have a header * of "BEGIN DH PARAMETERS". * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. * * Since: 3.1.3 **/ int gnutls_dh_params_export2_pkcs3(gnutls_dh_params_t params, gnutls_x509_crt_fmt_t format, gnutls_datum_t * out) { ASN1_TYPE c2; int result; size_t g_size, p_size; uint8_t *p_data, *g_data; uint8_t *all_data; _gnutls_mpi_print_lz(params->params[1], NULL, &g_size); _gnutls_mpi_print_lz(params->params[0], NULL, &p_size); all_data = gnutls_malloc(g_size + p_size); if (all_data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } p_data = &all_data[0]; _gnutls_mpi_print_lz(params->params[0], p_data, &p_size); g_data = &all_data[p_size]; _gnutls_mpi_print_lz(params->params[1], g_data, &g_size); /* Ok. Now we have the data. Create the asn1 structures */ if ((result = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.DHParameter", &c2)) != ASN1_SUCCESS) { gnutls_assert(); gnutls_free(all_data); return _gnutls_asn2err(result); } /* Write PRIME */ if ((result = asn1_write_value(c2, "prime", p_data, p_size)) != ASN1_SUCCESS) { gnutls_assert(); gnutls_free(all_data); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } if (params->q_bits > 0) result = _gnutls_x509_write_uint32(c2, "privateValueLength", params->q_bits); else result = asn1_write_value(c2, "privateValueLength", NULL, 0); if (result < 0) { gnutls_assert(); gnutls_free(all_data); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } /* Write the GENERATOR */ if ((result = asn1_write_value(c2, "base", g_data, g_size)) != ASN1_SUCCESS) { gnutls_assert(); gnutls_free(all_data); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } gnutls_free(all_data); if (format == GNUTLS_X509_FMT_DER) { result = _gnutls_x509_der_encode(c2, "", out, 0); asn1_delete_structure(&c2); if (result < 0) return gnutls_assert_val(result); } else { /* PEM */ gnutls_datum_t t; result = _gnutls_x509_der_encode(c2, "", &t, 0); asn1_delete_structure(&c2); if (result < 0) return gnutls_assert_val(result); result = _gnutls_fbase64_encode("DH PARAMETERS", t.data, t.size, out); gnutls_free(t.data); if (result < 0) { gnutls_assert(); return result; } } return 0; }
/* Writes the value of the datum in the given ASN1_TYPE. If str is non * zero it encodes it as OCTET STRING. */ int _gnutls_x509_write_value (ASN1_TYPE c, const char *root, const gnutls_datum_t * data, int str) { int result; int asize; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; gnutls_datum_t val; asize = data->size + 16; val.data = gnutls_malloc (asize); if (val.data == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } if (str) { /* Convert it to OCTET STRING */ if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.pkcs-7-Data", &c2)) != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_write_value (c2, "", data->data, data->size); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = _gnutls_x509_der_encode (c2, "", &val, 0); if (result < 0) { gnutls_assert (); goto cleanup; } } else { val.data = data->data; val.size = data->size; } /* Write the data. */ result = asn1_write_value (c, root, val.data, val.size); if (val.data != data->data) _gnutls_free_datum (&val); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } return 0; cleanup: if (val.data != data->data) _gnutls_free_datum (&val); return result; }
int _gnutls_x509_crq_set_extension (gnutls_x509_crq_t crq, const char *ext_id, const gnutls_datum_t * ext_data, unsigned int critical) { unsigned char *extensions = NULL; size_t extensions_size = 0; gnutls_datum_t der; ASN1_TYPE c2; int result; result = gnutls_x509_crq_get_attribute_by_oid (crq, "1.2.840.113549.1.9.14", 0, NULL, &extensions_size); if (result == GNUTLS_E_SHORT_MEMORY_BUFFER) { extensions = gnutls_malloc (extensions_size); if (extensions == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } result = gnutls_x509_crq_get_attribute_by_oid (crq, "1.2.840.113549.1.9.14", 0, extensions, &extensions_size); } if (result < 0) { if (result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { extensions_size = 0; } else { gnutls_assert (); gnutls_free (extensions); return result; } } result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.Extensions", &c2); if (result != ASN1_SUCCESS) { gnutls_assert (); gnutls_free (extensions); return _gnutls_asn2err (result); } if (extensions_size > 0) { result = asn1_der_decoding (&c2, extensions, extensions_size, NULL); gnutls_free (extensions); if (result != ASN1_SUCCESS) { gnutls_assert (); asn1_delete_structure (&c2); return _gnutls_asn2err (result); } } result = set_extension (c2, "", ext_id, ext_data, critical); if (result < 0) { gnutls_assert (); asn1_delete_structure (&c2); return result; } result = _gnutls_x509_der_encode (c2, "", &der, 0); asn1_delete_structure (&c2); if (result < 0) { gnutls_assert (); return result; } result = gnutls_x509_crq_set_attribute_by_oid (crq, "1.2.840.113549.1.9.14", der.data, der.size); gnutls_free (der.data); if (result < 0) { gnutls_assert (); return result; } return 0; }
/* generate the proxyCertInfo in a DER encoded extension */ int _gnutls_x509_ext_gen_proxyCertInfo (int pathLenConstraint, const char *policyLanguage, const char *policy, size_t sizeof_policy, gnutls_datum_t * der_ext) { ASN1_TYPE ext = ASN1_TYPE_EMPTY; int result; result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.ProxyCertInfo", &ext); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } if (pathLenConstraint < 0) { result = asn1_write_value (ext, "pCPathLenConstraint", NULL, 0); if (result < 0) result = _gnutls_asn2err (result); } else result = _gnutls_x509_write_uint32 (ext, "pCPathLenConstraint", pathLenConstraint); if (result < 0) { gnutls_assert (); asn1_delete_structure (&ext); return result; } result = asn1_write_value (ext, "proxyPolicy.policyLanguage", policyLanguage, 1); if (result < 0) { gnutls_assert (); asn1_delete_structure (&ext); return _gnutls_asn2err (result); } result = asn1_write_value (ext, "proxyPolicy.policy", policy, sizeof_policy); if (result < 0) { gnutls_assert (); asn1_delete_structure (&ext); return _gnutls_asn2err (result); } result = _gnutls_x509_der_encode (ext, "", der_ext, 0); asn1_delete_structure (&ext); if (result < 0) { gnutls_assert (); return result; } return 0; }
/* Encodes a private key to the raw format PKCS #8 needs. * For RSA it is a PKCS #1 DER private key and for DSA it is * an ASN.1 INTEGER of the x value. */ inline static int _encode_privkey(gnutls_x509_privkey_t pkey, gnutls_datum_t * raw) { int ret; ASN1_TYPE spk = ASN1_TYPE_EMPTY; switch (pkey->params.algo) { case GNUTLS_PK_EDDSA_ED25519: /* we encode as octet string (which is going to be stored inside * another octet string). No comments. */ ret = _gnutls_x509_encode_string(ASN1_ETYPE_OCTET_STRING, pkey->params.raw_priv.data, pkey->params.raw_priv.size, raw); if (ret < 0) gnutls_assert(); return ret; case GNUTLS_PK_GOST_01: case GNUTLS_PK_GOST_12_256: case GNUTLS_PK_GOST_12_512: if ((ret = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.GOSTPrivateKey", &spk)) != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto error; } ret = _gnutls_x509_write_key_int_le(spk, "", pkey->params.params[GOST_K]); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_x509_der_encode(spk, "", raw, 0); if (ret < 0) { gnutls_assert(); goto error; } asn1_delete_structure2(&spk, ASN1_DELETE_FLAG_ZEROIZE); break; case GNUTLS_PK_RSA: case GNUTLS_PK_RSA_PSS: case GNUTLS_PK_ECDSA: ret = _gnutls_x509_export_int2(pkey->key, GNUTLS_X509_FMT_DER, "", raw); if (ret < 0) { gnutls_assert(); goto error; } break; case GNUTLS_PK_DSA: /* DSAPublicKey == INTEGER */ if ((ret = asn1_create_element (_gnutls_get_gnutls_asn(), "GNUTLS.DSAPublicKey", &spk)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(ret); } ret = _gnutls_x509_write_int(spk, "", pkey->params.params[4], 1); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_x509_der_encode(spk, "", raw, 0); if (ret < 0) { gnutls_assert(); goto error; } asn1_delete_structure2(&spk, ASN1_DELETE_FLAG_ZEROIZE); break; default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } return 0; error: asn1_delete_structure2(&spk, ASN1_DELETE_FLAG_ZEROIZE); asn1_delete_structure(&spk); return ret; }
/* A generic export function. Will export the given ASN.1 encoded data * to PEM or DER raw data. */ int _gnutls_x509_export_int_named (ASN1_TYPE asn1_data, const char *name, gnutls_x509_crt_fmt_t format, const char *pem_header, unsigned char *output_data, size_t * output_data_size) { int result, len; if (format == GNUTLS_X509_FMT_DER) { if (output_data == NULL) *output_data_size = 0; len = *output_data_size; if ((result = asn1_der_coding (asn1_data, name, output_data, &len, NULL)) != ASN1_SUCCESS) { *output_data_size = len; if (result == ASN1_MEM_ERROR) { return GNUTLS_E_SHORT_MEMORY_BUFFER; } gnutls_assert (); return _gnutls_asn2err (result); } *output_data_size = len; } else { /* PEM */ opaque *out; gnutls_datum_t tmp; result = _gnutls_x509_der_encode (asn1_data, name, &tmp, 0); if (result < 0) { gnutls_assert (); return result; } result = _gnutls_fbase64_encode (pem_header, tmp.data, tmp.size, &out); _gnutls_free_datum (&tmp); if (result < 0) { gnutls_assert (); return result; } if (result == 0) { /* oooops */ gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } if ((unsigned) result > *output_data_size) { gnutls_assert (); gnutls_free (out); *output_data_size = result; return GNUTLS_E_SHORT_MEMORY_BUFFER; } *output_data_size = result; if (output_data) { memcpy (output_data, out, result); /* do not include the null character into output size. */ *output_data_size = result - 1; } gnutls_free (out); } return 0; }
/* encodes the Dss-Sig-Value structure */ int _gnutls_encode_ber_rs_raw(gnutls_datum_t * sig_value, const gnutls_datum_t * r, const gnutls_datum_t * s) { ASN1_TYPE sig; int result, ret; uint8_t *tmp = NULL; if ((result = asn1_create_element(_gnutls_get_gnutls_asn(), "GNUTLS.DSASignatureValue", &sig)) != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } if (s->data[0] >= 0x80 || r->data[0] >= 0x80) { tmp = gnutls_malloc(MAX(r->size, s->size)+1); if (tmp == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto cleanup; } } if (r->data[0] >= 0x80) { tmp[0] = 0; memcpy(&tmp[1], r->data, r->size); result = asn1_write_value(sig, "r", tmp, 1+r->size); } else { result = asn1_write_value(sig, "r", r->data, r->size); } if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } if (s->data[0] >= 0x80) { tmp[0] = 0; memcpy(&tmp[1], s->data, s->size); result = asn1_write_value(sig, "s", tmp, 1+s->size); } else { result = asn1_write_value(sig, "s", s->data, s->size); } if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } ret = _gnutls_x509_der_encode(sig, "", sig_value, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; cleanup: gnutls_free(tmp); asn1_delete_structure(&sig); return ret; }
/** * gnutls_x509_crt_set_policy: * @cert: should contain a #gnutls_x509_crt_t structure * @policy: A pointer to a policy structure. * @critical: use non-zero if the extension is marked as critical * * This function will set the certificate policy extension (2.5.29.32). * Multiple calls to this function append a new policy. * * Note the maximum text size for the qualifier %GNUTLS_X509_QUALIFIER_NOTICE * is 200 characters. This function will fail with %GNUTLS_E_INVALID_REQUEST * if this is exceeded. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1.5 **/ int gnutls_x509_crt_set_policy(gnutls_x509_crt_t crt, struct gnutls_x509_policy_st *policy, unsigned int critical) { int result; unsigned i; gnutls_datum_t der_data, tmpd, prev_der_data = { NULL, 0 }; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; const char *oid; if (crt == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } result = _gnutls_x509_crt_get_extension(crt, "2.5.29.32", 0, &prev_der_data, NULL); if (result < 0 && result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { gnutls_assert(); return result; } result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.certificatePolicies", &c2); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if (prev_der_data.data != NULL) { result = asn1_der_decoding(&c2, prev_der_data.data, prev_der_data.size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } } /* 1. write a new policy */ result = asn1_write_value(c2, "", "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } /* 2. Add the OID. */ result = asn1_write_value(c2, "?LAST.policyIdentifier", policy->oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } for (i = 0; i < MIN(policy->qualifiers, GNUTLS_MAX_QUALIFIERS); i++) { result = asn1_write_value(c2, "?LAST.policyQualifiers", "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if (policy->qualifier[i].type == GNUTLS_X509_QUALIFIER_URI) oid = "1.3.6.1.5.5.7.2.1"; else if (policy->qualifier[i].type == GNUTLS_X509_QUALIFIER_NOTICE) oid = "1.3.6.1.5.5.7.2.2"; else { result = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); goto cleanup; } result = asn1_write_value(c2, "?LAST.policyQualifiers.?LAST.policyQualifierId", oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if (policy->qualifier[i].type == GNUTLS_X509_QUALIFIER_URI) { tmpd.data = (void *) policy->qualifier[i].data; tmpd.size = policy->qualifier[i].size; result = _gnutls_x509_write_string(c2, "?LAST.policyQualifiers.?LAST.qualifier", &tmpd, ASN1_ETYPE_IA5_STRING); if (result < 0) { gnutls_assert(); goto cleanup; } } else if (policy->qualifier[i].type == GNUTLS_X509_QUALIFIER_NOTICE) { tmpd.data = (void *) policy->qualifier[i].data; tmpd.size = policy->qualifier[i].size; if (tmpd.size > 200) { gnutls_assert(); result = GNUTLS_E_INVALID_REQUEST; goto cleanup; } result = encode_user_notice(&tmpd, &der_data); if (result < 0) { gnutls_assert(); goto cleanup; } result = _gnutls_x509_write_value(c2, "?LAST.policyQualifiers.?LAST.qualifier", &der_data); _gnutls_free_datum(&der_data); if (result < 0) { gnutls_assert(); goto cleanup; } } } result = _gnutls_x509_der_encode(c2, "", &der_data, 0); if (result < 0) { gnutls_assert(); goto cleanup; } result = _gnutls_x509_crt_set_extension(crt, "2.5.29.32", &der_data, 0); _gnutls_free_datum(&der_data); crt->use_extensions = 1; cleanup: asn1_delete_structure(&c2); _gnutls_free_datum(&prev_der_data); return result; }
/** * gnutls_x509_crt_set_authority_info_access: * @crt: Holds the certificate * @what: what data to get, a #gnutls_info_access_what_t type. * @data: output data to be freed with gnutls_free(). * * This function sets the Authority Information Access (AIA) * extension, see RFC 5280 section 4.2.2.1 for more information. * * The type of data stored in @data is specified via @what which * should be #gnutls_info_access_what_t values. * * If @what is %GNUTLS_IA_OCSP_URI, @data will hold the OCSP URI. * If @what is %GNUTLS_IA_CAISSUERS_URI, @data will hold the caIssuers * URI. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0 **/ int gnutls_x509_crt_set_authority_info_access(gnutls_x509_crt_t crt, int what, gnutls_datum_t * data) { int ret, result; gnutls_datum_t aia = { NULL, 0 }; gnutls_datum_t der_data = { NULL, 0 }; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; const char *oid; unsigned int c; if (crt == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); oid = what_to_oid(what); if (oid == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ret = asn1_create_element(_gnutls_get_pkix(), "PKIX1.AuthorityInfoAccessSyntax", &c2); if (ret != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(ret); } ret = _gnutls_x509_crt_get_extension(crt, GNUTLS_OID_AIA, 0, &aia, &c); if (ret >= 0) { /* decode it */ ret = asn1_der_decoding(&c2, aia.data, aia.size, NULL); if (ret != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } } /* generate the extension. */ /* 1. create a new element. */ result = asn1_write_value(c2, "", "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } /* 2. Add the OID. */ result = asn1_write_value(c2, "?LAST.accessMethod", oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } /* accessLocation is a choice */ result = asn1_write_value(c2, "?LAST.accessLocation", "uniformResourceIdentifier", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(c2, "?LAST.accessLocation.uniformResourceIdentifier", data->data, data->size); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } ret = _gnutls_x509_der_encode(c2, "", &der_data, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_x509_crt_set_extension(crt, GNUTLS_OID_AIA, &der_data, 0); if (ret < 0) gnutls_assert(); crt->use_extensions = 1; cleanup: _gnutls_free_datum(&der_data); _gnutls_free_datum(&aia); asn1_delete_structure(&c2); return ret; }
/** * gnutls_x509_crt_set_key_purpose_oid: * @cert: a certificate of type #gnutls_x509_crt_t * @oid: a pointer to a null terminated string that holds the OID * @critical: Whether this extension will be critical or not * * This function will set the key purpose OIDs of the Certificate. * These are stored in the Extended Key Usage extension (2.5.29.37) * See the GNUTLS_KP_* definitions for human readable names. * * Subsequent calls to this function will append OIDs to the OID list. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. **/ int gnutls_x509_crt_set_key_purpose_oid(gnutls_x509_crt_t cert, const void *oid, unsigned int critical) { int result; gnutls_datum_t old_id, der_data; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; if (cert == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } result = asn1_create_element (_gnutls_get_pkix(), "PKIX1.ExtKeyUsageSyntax", &c2); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } /* Check if the extension already exists. */ result = _gnutls_x509_crt_get_extension(cert, "2.5.29.37", 0, &old_id, NULL); if (result >= 0) { /* decode it. */ result = asn1_der_decoding(&c2, old_id.data, old_id.size, NULL); _gnutls_free_datum(&old_id); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } } /* generate the extension. */ /* 1. create a new element. */ result = asn1_write_value(c2, "", "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } /* 2. Add the OID. */ result = asn1_write_value(c2, "?LAST", oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); asn1_delete_structure(&c2); return _gnutls_asn2err(result); } result = _gnutls_x509_der_encode(c2, "", &der_data, 0); asn1_delete_structure(&c2); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } result = _gnutls_x509_crt_set_extension(cert, "2.5.29.37", &der_data, critical); _gnutls_free_datum(&der_data); if (result < 0) { gnutls_assert(); return result; } cert->use_extensions = 1; return 0; }
int _gnutls_krb5_principal_to_der(const char *name, gnutls_datum_t * der) { int ret, result; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; krb5_principal_data *princ; unsigned i; princ = name_to_principal(name); if (princ == NULL) { gnutls_assert(); ret = GNUTLS_E_PARSING_ERROR; goto cleanup; } result = asn1_create_element(_gnutls_get_gnutls_asn(), "GNUTLS.KRB5PrincipalName", &c2); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(c2, "realm", princ->realm, strlen(princ->realm)); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(c2, "principalName.name-type", &princ->type, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } for (i = 0; i < princ->length; i++) { result = asn1_write_value(c2, "principalName.name-string", "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } result = asn1_write_value(c2, "principalName.name-string.?LAST", princ->data[i], strlen(princ->data[i])); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } } ret = _gnutls_x509_der_encode(c2, "", der, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; cleanup: cleanup_principal(princ); asn1_delete_structure(&c2); return ret; }
/* Creates and encodes the CRL Distribution points. data_string should be a name * and type holds the type of the name. * reason_flags should be an or'ed sequence of GNUTLS_CRL_REASON_*. * */ int _gnutls_x509_ext_gen_crl_dist_points (gnutls_x509_subject_alt_name_t type, const void *data, unsigned int data_size, unsigned int reason_flags, gnutls_datum_t * der_ext) { ASN1_TYPE ext = ASN1_TYPE_EMPTY; gnutls_datum_t gnames = { NULL, 0 }; int result; uint8_t reasons[2]; reasons[0] = reason_flags & 0xff; reasons[1] = reason_flags >> 8; result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.CRLDistributionPoints", &ext); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_write_value (ext, "", "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (reason_flags) { result = asn1_write_value (ext, "?LAST.reasons", reasons, 9); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } } else { result = asn1_write_value (ext, "?LAST.reasons", NULL, 0); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } } result = asn1_write_value (ext, "?LAST.cRLIssuer", NULL, 0); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* When used as type CHOICE. */ result = asn1_write_value (ext, "?LAST.distributionPoint", "fullName", 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } #if 0 /* only needed in old code (where defined as SEQUENCE OF) */ asn1_write_value (ext, "?LAST.distributionPoint.nameRelativeToCRLIssuer", NULL, 0); #endif result = write_new_general_name (ext, "?LAST.distributionPoint.fullName", type, data, data_size); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_der_encode (ext, "", der_ext, 0); if (result < 0) { gnutls_assert (); goto cleanup; } result = 0; cleanup: _gnutls_free_datum (&gnames); asn1_delete_structure (&ext); return result; }
/** * gnutls_pkcs12_bag_encrypt: * @bag: The bag * @pass: The password used for encryption, must be ASCII * @flags: should be one of #gnutls_pkcs_encrypt_flags_t elements bitwise or'd * * This function will encrypt the given bag. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. **/ int gnutls_pkcs12_bag_encrypt(gnutls_pkcs12_bag_t bag, const char *pass, unsigned int flags) { int ret; ASN1_TYPE safe_cont = ASN1_TYPE_EMPTY; gnutls_datum_t der = { NULL, 0 }; gnutls_datum_t enc = { NULL, 0 }; schema_id id; if (bag == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } if (bag->element[0].type == GNUTLS_BAG_ENCRYPTED) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } /* Encode the whole bag to a safe contents * structure. */ ret = _pkcs12_encode_safe_contents(bag, &safe_cont, NULL); if (ret < 0) { gnutls_assert(); return ret; } /* DER encode the SafeContents. */ ret = _gnutls_x509_der_encode(safe_cont, "", &der, 0); asn1_delete_structure(&safe_cont); if (ret < 0) { gnutls_assert(); return ret; } if (flags & GNUTLS_PKCS_PLAIN) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } id = _gnutls_pkcs_flags_to_schema(flags); /* Now encrypt them. */ ret = _gnutls_pkcs7_encrypt_data(id, &der, pass, &enc); _gnutls_free_datum(&der); if (ret < 0) { gnutls_assert(); return ret; } /* encryption succeeded. */ _pkcs12_bag_free_data(bag); bag->element[0].type = GNUTLS_BAG_ENCRYPTED; bag->element[0].data = enc; bag->bag_elements = 1; return 0; }
int _pkcs12_encode_crt_bag (gnutls_pkcs12_bag_type_t type, const gnutls_datum_t * raw, gnutls_datum_t * out) { int ret; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; if (type == GNUTLS_BAG_CERTIFICATE) { if ((ret = asn1_create_element (_gnutls_get_pkix (), "PKIX1.pkcs-12-CertBag", &c2)) != ASN1_SUCCESS) { gnutls_assert (); ret = _gnutls_asn2err (ret); goto cleanup; } ret = asn1_write_value (c2, "certId", X509_CERT_OID, 1); if (ret != ASN1_SUCCESS) { gnutls_assert (); ret = _gnutls_asn2err (ret); goto cleanup; } ret = _gnutls_x509_write_value (c2, "certValue", raw, 1); if (ret < 0) { gnutls_assert (); goto cleanup; } } else { /* CRL */ if ((ret = asn1_create_element (_gnutls_get_pkix (), "PKIX1.pkcs-12-CRLBag", &c2)) != ASN1_SUCCESS) { gnutls_assert (); ret = _gnutls_asn2err (ret); goto cleanup; } ret = asn1_write_value (c2, "crlId", X509_CRL_OID, 1); if (ret != ASN1_SUCCESS) { gnutls_assert (); ret = _gnutls_asn2err (ret); goto cleanup; } ret = _gnutls_x509_write_value (c2, "crlValue", raw, 1); if (ret < 0) { gnutls_assert (); goto cleanup; } } ret = _gnutls_x509_der_encode (c2, "", out, 0); if (ret < 0) { gnutls_assert (); goto cleanup; } asn1_delete_structure (&c2); return 0; cleanup: asn1_delete_structure (&c2); return ret; }
int _pkcs12_encode_crt_bag(gnutls_pkcs12_bag_type_t type, const gnutls_datum_t * raw, gnutls_datum_t * out) { int ret; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; switch (type) { case GNUTLS_BAG_CERTIFICATE: if ((ret = asn1_create_element(_gnutls_get_pkix(), "PKIX1.pkcs-12-CertBag", &c2)) != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } ret = asn1_write_value(c2, "certId", X509_CERT_OID, 1); if (ret != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } ret = _gnutls_x509_write_string(c2, "certValue", raw, ASN1_ETYPE_OCTET_STRING); if (ret < 0) { gnutls_assert(); goto cleanup; } break; case GNUTLS_BAG_CRL: if ((ret = asn1_create_element(_gnutls_get_pkix(), "PKIX1.pkcs-12-CRLBag", &c2)) != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } ret = asn1_write_value(c2, "crlId", X509_CRL_OID, 1); if (ret != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } ret = _gnutls_x509_write_string(c2, "crlValue", raw, ASN1_ETYPE_OCTET_STRING); if (ret < 0) { gnutls_assert(); goto cleanup; } break; case GNUTLS_BAG_SECRET: if ((ret = asn1_create_element(_gnutls_get_pkix(), "PKIX1.pkcs-12-SecretBag", &c2)) != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } ret = asn1_write_value(c2, "secretTypeId", RANDOM_NONCE_OID, 1); if (ret != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(ret); goto cleanup; } ret = _gnutls_x509_write_string(c2, "secretValue", raw, ASN1_ETYPE_OCTET_STRING); if (ret < 0) { gnutls_assert(); goto cleanup; } break; default: gnutls_assert(); asn1_delete_structure(&c2); return GNUTLS_E_UNIMPLEMENTED_FEATURE; } ret = _gnutls_x509_der_encode(c2, "", out, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } asn1_delete_structure(&c2); return 0; cleanup: asn1_delete_structure(&c2); return ret; }