/** * gnutls_ext_register - Register a handler for a TLS extension * @type: the 16-bit integer referring to the extension type * @name: human printable name of the extension used for debugging * @parse_type: either #GNUTLS_EXT_TLS or %GNUTLS_EXT_APPLICATION. * @recv_func: a function to receive extension data * @send_func: a function to send extension data * * This function is used to register a new TLS extension handler. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. * * Since: 2.6.0 **/ int gnutls_ext_register (int type, const char *name, gnutls_ext_parse_type_t parse_type, gnutls_ext_recv_func recv_func, gnutls_ext_send_func send_func) { gnutls_extension_entry *p; p = gnutls_realloc (extfunc, sizeof (*extfunc) * (extfunc_size + 1)); if (!p) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } extfunc = p; extfunc[extfunc_size].type = type; extfunc[extfunc_size].name = name; extfunc[extfunc_size].parse_type = parse_type; extfunc[extfunc_size].recv_func = recv_func; extfunc[extfunc_size].send_func = send_func; extfunc_size++; return GNUTLS_E_SUCCESS; }
/* This function will return the internal (per session) temporary * recv buffer. If the buffer was not initialized before it will * also initialize it. */ inline static int get_temp_recv_buffer (gnutls_session_t session, gnutls_datum_t * tmp) { /* We allocate MAX_RECORD_RECV_SIZE length * because we cannot predict the output data by the record * packet length (due to compression). */ if (MAX_RECORD_RECV_SIZE > session->internals.recv_buffer.size || session->internals.recv_buffer.data == NULL) { /* Initialize the internal buffer. */ session->internals.recv_buffer.data = gnutls_realloc (session->internals.recv_buffer.data, MAX_RECORD_RECV_SIZE); if (session->internals.recv_buffer.data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } session->internals.recv_buffer.size = MAX_RECORD_RECV_SIZE; } tmp->data = session->internals.recv_buffer.data; tmp->size = session->internals.recv_buffer.size; return 0; }
int _gnutls_datum_append (gnutls_datum_t * dst, const void *data, size_t data_size) { dst->data = gnutls_realloc (dst->data, data_size + dst->size); if (dst->data == NULL) return GNUTLS_E_MEMORY_ERROR; memcpy (&dst->data[dst->size], data, data_size); dst->size += data_size; return 0; }
int _gnutls_buffer_append_data (gnutls_buffer_st * dest, const void *data, size_t data_size) { size_t tot_len = data_size + dest->length; if (data_size == 0) return 0; if (dest->max_length >= tot_len) { size_t unused = MEMSUB (dest->data, dest->allocd); if (dest->max_length - unused <= tot_len) { if (dest->length && dest->data) memmove (dest->allocd, dest->data, dest->length); dest->data = dest->allocd; } memmove (&dest->data[dest->length], data, data_size); dest->length = tot_len; return tot_len; } else { size_t unused = MEMSUB (dest->data, dest->allocd); size_t new_len = MAX (data_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK); dest->allocd = gnutls_realloc (dest->allocd, new_len); if (dest->allocd == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } dest->max_length = new_len; dest->data = dest->allocd + unused; if (dest->length && dest->data) memmove (dest->allocd, dest->data, dest->length); dest->data = dest->allocd; memcpy (&dest->data[dest->length], data, data_size); dest->length = tot_len; return tot_len; } }
/* Checks if the extra_certs contain certificates that may form a chain * with the first certificate in chain (it is expected that chain_len==1) * and appends those in the chain. */ static int make_chain(gnutls_x509_crt_t **chain, unsigned int *chain_len, gnutls_x509_crt_t **extra_certs, unsigned int *extra_certs_len, unsigned int flags) { unsigned int i; if (*chain_len != 1) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); i = 0; while(i<*extra_certs_len) { /* if it is an issuer but not a self-signed one */ if (gnutls_x509_crt_check_issuer((*chain)[*chain_len - 1], (*extra_certs)[i]) != 0) { if (!(flags & GNUTLS_PKCS12_SP_INCLUDE_SELF_SIGNED) && gnutls_x509_crt_check_issuer((*extra_certs)[i], (*extra_certs)[i]) != 0) goto skip; *chain = gnutls_realloc (*chain, sizeof((*chain)[0]) * ++(*chain_len)); if (*chain == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } (*chain)[*chain_len - 1] = (*extra_certs)[i]; (*extra_certs)[i] = (*extra_certs)[*extra_certs_len-1]; (*extra_certs_len)--; i=0; continue; } skip: i++; } return 0; }
/* This function will return the internal (per session) temporary * recv buffer. If the buffer was not initialized before it will * also initialize it. */ inline static int get_temp_recv_buffer (gnutls_session_t session, gnutls_datum_t * tmp) { size_t max_record_size; if (gnutls_compression_get (session) != GNUTLS_COMP_NULL || session->internals.priorities.allow_large_records != 0) max_record_size = MAX_RECORD_RECV_SIZE + EXTRA_COMP_SIZE; else max_record_size = MAX_RECORD_RECV_SIZE; /* We allocate MAX_RECORD_RECV_SIZE length * because we cannot predict the output data by the record * packet length (due to compression). */ if (max_record_size > session->internals.recv_buffer.size || session->internals.recv_buffer.data == NULL) { /* Initialize the internal buffer. */ session->internals.recv_buffer.data = gnutls_realloc (session->internals.recv_buffer.data, max_record_size); if (session->internals.recv_buffer.data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } session->internals.recv_buffer.size = max_record_size; } tmp->data = session->internals.recv_buffer.data; tmp->size = session->internals.recv_buffer.size; return 0; }
int _gnutls_buffer_resize (gnutls_buffer_st * dest, size_t new_size) { if (dest->max_length >= new_size) { size_t unused = MEMSUB (dest->data, dest->allocd); if (dest->max_length - unused <= new_size) { if (dest->length && dest->data) memmove (dest->allocd, dest->data, dest->length); dest->data = dest->allocd; } return 0; } else { size_t unused = MEMSUB (dest->data, dest->allocd); size_t alloc_len = MAX (new_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK); dest->allocd = gnutls_realloc (dest->allocd, alloc_len); if (dest->allocd == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } dest->max_length = alloc_len; dest->data = dest->allocd + unused; if (dest->length && dest->data) memmove (dest->allocd, dest->data, dest->length); dest->data = dest->allocd; return 0; } }
/* Checks if the extra_certs contain certificates that may form a chain * with the first certificate in chain (it is expected that chain_len==1) * and appends those in the chain. */ static int make_chain(gnutls_x509_crt_t **chain, unsigned int *chain_len, gnutls_x509_crt_t **extra_certs, unsigned int *extra_certs_len) { unsigned int i; if (*chain_len != 1) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); i = 0; while(i<*extra_certs_len) { /* if it is an issuer but not a self-signed one */ if (gnutls_x509_crt_check_issuer((*chain)[*chain_len - 1], (*extra_certs)[i]) != 0 && gnutls_x509_crt_check_issuer((*extra_certs)[i], (*extra_certs)[i]) == 0) { void *tmp = *chain; *chain = gnutls_realloc (*chain, sizeof((*chain)[0]) * ++(*chain_len)); if (*chain == NULL) { gnutls_assert(); gnutls_free(tmp); return GNUTLS_E_MEMORY_ERROR; } (*chain)[*chain_len - 1] = (*extra_certs)[i]; (*extra_certs)[i] = (*extra_certs)[*extra_certs_len-1]; (*extra_certs_len)--; i=0; continue; } i++; } return 0; }
/* Like above but it accepts a parsed certificate instead. */ int _gnutls_x509_crt_to_gcert (gnutls_cert * gcert, gnutls_x509_crt_t cert, unsigned int flags) { int ret = 0; memset (gcert, 0, sizeof (gnutls_cert)); gcert->cert_type = GNUTLS_CRT_X509; if (!(flags & CERT_NO_COPY)) { #define SMALL_DER 512 opaque *der; size_t der_size = SMALL_DER; /* initially allocate a bogus size, just in case the certificate * fits in it. That way we minimize the DER encodings performed. */ der = gnutls_malloc (SMALL_DER); if (der == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert (); gnutls_free (der); return ret; } if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { der = gnutls_realloc (der, der_size); if (der == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0) { gnutls_assert (); gnutls_free (der); return ret; } } gcert->raw.data = der; gcert->raw.size = der_size; } else /* now we have 0 or a bitwise or of things to decode */ flags ^= CERT_NO_COPY; if (flags & CERT_ONLY_EXTENSIONS || flags == 0) { gnutls_x509_crt_get_key_usage (cert, &gcert->key_usage, NULL); gcert->version = gnutls_x509_crt_get_version (cert); } gcert->subject_pk_algorithm = gnutls_x509_crt_get_pk_algorithm (cert, NULL); if (flags & CERT_ONLY_PUBKEY || flags == 0) { gcert->params_size = MAX_PUBLIC_PARAMS_SIZE; ret = _gnutls_x509_crt_get_mpis (cert, gcert->params, &gcert->params_size); if (ret < 0) { gnutls_assert (); return ret; } } return 0; }
/** * gnutls_pkcs12_simple_parse: * @p12: the PKCS#12 blob. * @password: optional password used to decrypt PKCS#12 blob, bags and keys. * @key: a structure to store the parsed private key. * @chain: the corresponding to key certificate chain * @chain_len: will be updated with the number of additional * @extra_certs: optional pointer to receive an array of additional * certificates found in the PKCS#12 blob. * @extra_certs_len: will be updated with the number of additional * certs. * @crl: an optional structure to store the parsed CRL. * @flags: should be zero * * This function parses a PKCS#12 blob in @p12blob and extracts the * private key, the corresponding certificate chain, and any additional * certificates and a CRL. * * The @extra_certs_ret and @extra_certs_ret_len parameters are optional * and both may be set to %NULL. If either is non-%NULL, then both must * be. * * MAC:ed PKCS#12 files are supported. Encrypted PKCS#12 bags are * supported. Encrypted PKCS#8 private keys are supported. However, * only password based security, and the same password for all * operations, are supported. * * The private keys may be RSA PKCS#1 or DSA private keys encoded in * the OpenSSL way. * * PKCS#12 file may contain many keys and/or certificates, and there * is no way to identify which key/certificate pair you want. You * should make sure the PKCS#12 file only contain one key/certificate * pair and/or one CRL. * * It is believed that the limitations of this function is acceptable * for most usage, and that any more flexibility would introduce * complexity that would make it harder to use this functionality at * all. * * If the provided structure has encrypted fields but no password * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1 **/ int gnutls_pkcs12_simple_parse (gnutls_pkcs12_t p12, const char *password, gnutls_x509_privkey_t * key, gnutls_x509_crt_t ** chain, unsigned int * chain_len, gnutls_x509_crt_t ** extra_certs, unsigned int * extra_certs_len, gnutls_x509_crl_t * crl, unsigned int flags) { gnutls_pkcs12_bag_t bag = NULL; gnutls_x509_crt_t *_extra_certs = NULL; unsigned int _extra_certs_len = 0; gnutls_x509_crt_t *_chain = NULL; unsigned int _chain_len = 0; int idx = 0; int ret; size_t cert_id_size = 0; size_t key_id_size = 0; opaque cert_id[20]; opaque key_id[20]; int privkey_ok = 0; *key = NULL; if (crl) *crl = NULL; /* find the first private key */ for (;;) { int elements_in_bag; int i; ret = gnutls_pkcs12_bag_init (&bag); if (ret < 0) { bag = NULL; gnutls_assert (); goto done; } ret = gnutls_pkcs12_get_bag (p12, idx, bag); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_type (bag, 0); if (ret < 0) { gnutls_assert (); goto done; } if (ret == GNUTLS_BAG_ENCRYPTED) { if (password == NULL) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto done; } ret = gnutls_pkcs12_bag_decrypt (bag, password); if (ret < 0) { gnutls_assert (); goto done; } } elements_in_bag = gnutls_pkcs12_bag_get_count (bag); if (elements_in_bag < 0) { gnutls_assert (); goto done; } for (i = 0; i < elements_in_bag; i++) { int type; gnutls_datum_t data; type = gnutls_pkcs12_bag_get_type (bag, i); if (type < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_data (bag, i, &data); if (ret < 0) { gnutls_assert (); goto done; } switch (type) { case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: if (password == NULL) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto done; } case GNUTLS_BAG_PKCS8_KEY: if (*key != NULL) /* too simple to continue */ { gnutls_assert (); break; } ret = gnutls_x509_privkey_init (key); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_privkey_import_pkcs8 (*key, &data, GNUTLS_X509_FMT_DER, password, type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0); if (ret < 0) { gnutls_assert (); gnutls_x509_privkey_deinit (*key); goto done; } key_id_size = sizeof (key_id); ret = gnutls_x509_privkey_get_key_id (*key, 0, key_id, &key_id_size); if (ret < 0) { gnutls_assert (); gnutls_x509_privkey_deinit (*key); goto done; } privkey_ok = 1; /* break */ break; default: break; } } idx++; gnutls_pkcs12_bag_deinit (bag); if (privkey_ok != 0) /* private key was found */ break; } if (privkey_ok == 0) /* no private key */ { gnutls_assert (); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } /* now find the corresponding certificate */ idx = 0; bag = NULL; for (;;) { int elements_in_bag; int i; ret = gnutls_pkcs12_bag_init (&bag); if (ret < 0) { bag = NULL; gnutls_assert (); goto done; } ret = gnutls_pkcs12_get_bag (p12, idx, bag); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_type (bag, 0); if (ret < 0) { gnutls_assert (); goto done; } if (ret == GNUTLS_BAG_ENCRYPTED) { ret = gnutls_pkcs12_bag_decrypt (bag, password); if (ret < 0) { gnutls_assert (); goto done; } } elements_in_bag = gnutls_pkcs12_bag_get_count (bag); if (elements_in_bag < 0) { gnutls_assert (); goto done; } for (i = 0; i < elements_in_bag; i++) { int type; gnutls_datum_t data; gnutls_x509_crt_t this_cert; type = gnutls_pkcs12_bag_get_type (bag, i); if (type < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_data (bag, i, &data); if (ret < 0) { gnutls_assert (); goto done; } switch (type) { case GNUTLS_BAG_CERTIFICATE: ret = gnutls_x509_crt_init (&this_cert); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_crt_import (this_cert, &data, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); gnutls_x509_crt_deinit (this_cert); goto done; } /* check if the key id match */ cert_id_size = sizeof (cert_id); ret = gnutls_x509_crt_get_key_id (this_cert, 0, cert_id, &cert_id_size); if (ret < 0) { gnutls_assert (); gnutls_x509_crt_deinit (this_cert); goto done; } if (memcmp (cert_id, key_id, cert_id_size) != 0) { /* they don't match - skip the certificate */ if (extra_certs) { void *tmp = _extra_certs; _extra_certs = gnutls_realloc (_extra_certs, sizeof(_extra_certs[0]) * ++_extra_certs_len); if (!_extra_certs) { gnutls_assert (); gnutls_free(tmp); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _extra_certs[_extra_certs_len - 1] = this_cert; this_cert = NULL; } else { gnutls_x509_crt_deinit (this_cert); } } else { if (_chain_len == 0) { _chain = gnutls_malloc (sizeof(_chain[0]) * (++_chain_len)); if (!_chain) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _chain[_chain_len - 1] = this_cert; this_cert = NULL; } else { gnutls_x509_crt_deinit (this_cert); } } break; case GNUTLS_BAG_CRL: if (crl == NULL || *crl != NULL) { gnutls_assert (); break; } ret = gnutls_x509_crl_init (crl); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_crl_import (*crl, &data, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); gnutls_x509_crl_deinit (*crl); goto done; } break; case GNUTLS_BAG_ENCRYPTED: /* XXX Bother to recurse one level down? Unlikely to use the same password anyway. */ case GNUTLS_BAG_EMPTY: default: break; } } idx++; gnutls_pkcs12_bag_deinit (bag); } if (_chain_len != 1) { ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto done; } ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len); if (ret < 0) { gnutls_assert(); goto done; } ret = 0; done: if (bag) gnutls_pkcs12_bag_deinit (bag); if (ret < 0) { if (*key) gnutls_x509_privkey_deinit(*key); if (_extra_certs_len && _extra_certs != NULL) { unsigned int i; for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (_chain_len && _chain != NULL) { unsigned int i; for (i = 0; i < _chain_len; i++) gnutls_x509_crt_deinit(_chain[i]); gnutls_free(_chain); } } else { if (extra_certs) { *extra_certs = _extra_certs; *extra_certs_len = _extra_certs_len; } *chain = _chain; *chain_len = _chain_len; } return ret; }
/** * gnutls_x509_trust_list_add_crls: * @list: The list * @crl_list: A list of CRLs * @crl_size: The length of the CRL list * @flags: flags from %gnutls_trust_list_flags_t * @verification_flags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL * * This function will add the given certificate revocation lists * to the trusted list. The CRLs in @crl_list must not be deinitialized * during the lifetime of @list. * * This function must be called after gnutls_x509_trust_list_add_cas() * to allow verifying the CRLs for validity. If the flag %GNUTLS_TL_NO_DUPLICATES * is given, then the final CRL list will not contain duplicate entries. * * If the flag %GNUTLS_TL_NO_DUPLICATES is given, gnutls_x509_trust_list_deinit() must be * called with parameter @all being 1. * * If flag %GNUTLS_TL_VERIFY_CRL is given the CRLs will be verified before being added, * and if verification fails, they will be skipped. * * Returns: The number of added elements is returned; that includes * duplicate entries. * * Since: 3.0 **/ int gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list, const gnutls_x509_crl_t * crl_list, unsigned crl_size, unsigned int flags, unsigned int verification_flags) { int ret; unsigned x, i, j = 0; unsigned int vret = 0; uint32_t hash; gnutls_x509_crl_t *tmp; /* Probably we can optimize things such as removing duplicates * etc. */ if (crl_size == 0 || crl_list == NULL) return 0; for (i = 0; i < crl_size; i++) { hash = hash_pjw_bare(crl_list[i]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size); hash %= list->size; if (flags & GNUTLS_TL_VERIFY_CRL) { ret = gnutls_x509_crl_verify(crl_list[i], list->node[hash]. trusted_cas, list->node[hash]. trusted_ca_size, verification_flags, &vret); if (ret < 0 || vret != 0) { _gnutls_debug_log("CRL verification failed, not adding it\n"); if (flags & GNUTLS_TL_NO_DUPLICATES) gnutls_x509_crl_deinit(crl_list[i]); if (flags & GNUTLS_TL_FAIL_ON_INVALID_CRL) return gnutls_assert_val(GNUTLS_E_CRL_VERIFICATION_ERROR); continue; } } /* If the CRL added overrides a previous one, then overwrite * the old one */ if (flags & GNUTLS_TL_NO_DUPLICATES) { for (x=0;x<list->node[hash].crl_size;x++) { if (crl_list[i]->raw_issuer_dn.size == list->node[hash].crls[x]->raw_issuer_dn.size && memcmp(crl_list[i]->raw_issuer_dn.data, list->node[hash].crls[x]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size) == 0) { if (gnutls_x509_crl_get_this_update(crl_list[i]) >= gnutls_x509_crl_get_this_update(list->node[hash].crls[x])) { gnutls_x509_crl_deinit(list->node[hash].crls[x]); list->node[hash].crls[x] = crl_list[i]; goto next; } else { /* The new is older, discard it */ gnutls_x509_crl_deinit(crl_list[i]); goto next; } } } } tmp = gnutls_realloc(list->node[hash].crls, (list->node[hash].crl_size + 1) * sizeof(list->node[hash]. crls[0])); if (tmp == NULL) { ret = i; gnutls_assert(); if (flags & GNUTLS_TL_NO_DUPLICATES) while (i < crl_size) gnutls_x509_crl_deinit(crl_list[i++]); return ret; } list->node[hash].crls = tmp; list->node[hash].crls[list->node[hash].crl_size] = crl_list[i]; list->node[hash].crl_size++; next: j++; } return j; }
/* Converts a parsed gnutls_openpgp_crt_t to a gnutls_cert structure. */ int _gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert, gnutls_openpgp_crt_t cert) { int ret; gnutls_openpgp_keyid_t keyid; char err_buf[33]; memset (gcert, 0, sizeof (gnutls_cert)); gcert->cert_type = GNUTLS_CRT_OPENPGP; gcert->version = gnutls_openpgp_crt_get_version (cert); gcert->params_size = MAX_PUBLIC_PARAMS_SIZE; ret = gnutls_openpgp_crt_get_preferred_key_id (cert, keyid); if (ret == 0) { int idx; uint32_t kid32[2]; _gnutls_debug_log ("Importing Openpgp cert and using openpgp sub key: %s\n", _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf))); KEYID_IMPORT (kid32, keyid); idx = gnutls_openpgp_crt_get_subkey_idx (cert, keyid); if (idx < 0) { gnutls_assert (); return idx; } gcert->subject_pk_algorithm = gnutls_openpgp_crt_get_subkey_pk_algorithm (cert, idx, NULL); gnutls_openpgp_crt_get_subkey_usage (cert, idx, &gcert->key_usage); gcert->use_subkey = 1; memcpy (gcert->subkey_id, keyid, sizeof (keyid)); ret = _gnutls_openpgp_crt_get_mpis (cert, kid32, gcert->params, &gcert->params_size); } else { _gnutls_debug_log ("Importing Openpgp cert and using main openpgp key\n"); gcert->subject_pk_algorithm = gnutls_openpgp_crt_get_pk_algorithm (cert, NULL); gnutls_openpgp_crt_get_key_usage (cert, &gcert->key_usage); ret = _gnutls_openpgp_crt_get_mpis (cert, NULL, gcert->params, &gcert->params_size); gcert->use_subkey = 0; } if (ret < 0) { gnutls_assert (); return ret; } { /* copy the raw certificate */ #define SMALL_RAW 512 opaque *raw; size_t raw_size = SMALL_RAW; /* initially allocate a bogus size, just in case the certificate * fits in it. That way we minimize the DER encodings performed. */ raw = gnutls_malloc (raw_size); if (raw == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_openpgp_crt_export (cert, GNUTLS_OPENPGP_FMT_RAW, raw, &raw_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert (); gnutls_free (raw); return ret; } if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { raw = gnutls_realloc (raw, raw_size); if (raw == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_openpgp_crt_export (cert, GNUTLS_OPENPGP_FMT_RAW, raw, &raw_size); if (ret < 0) { gnutls_assert (); gnutls_free (raw); return ret; } } gcert->raw.data = raw; gcert->raw.size = raw_size; } return 0; }