/* Reads a DER encoded certificate list from memory and stores it to a * gnutls_cert structure. Returns the number of certificates parsed. */ static int parse_crt_mem (gnutls_cert ** cert_list, unsigned *ncerts, gnutls_x509_crt_t cert) { int i; int ret; i = *ncerts + 1; *cert_list = (gnutls_cert *) gnutls_realloc_fast (*cert_list, i * sizeof (gnutls_cert)); if (*cert_list == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_x509_crt_to_gcert (&cert_list[0][i - 1], cert, 0); if (ret < 0) { gnutls_assert (); return ret; } *ncerts = i; return 1; /* one certificate parsed */ }
/* Reads a DER or PEM certificate from memory */ static int read_cert_mem (gnutls_certificate_credentials_t res, const void *cert, int cert_size, gnutls_x509_crt_fmt_t type) { int ret; /* allocate space for the certificate to add */ res->cert_list = gnutls_realloc_fast (res->cert_list, (1 + res->ncerts) * sizeof (gnutls_cert *)); if (res->cert_list == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } res->cert_list_length = gnutls_realloc_fast (res->cert_list_length, (1 + res->ncerts) * sizeof (int)); if (res->cert_list_length == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } res->cert_list[res->ncerts] = NULL; /* for realloc */ res->cert_list_length[res->ncerts] = 0; if (type == GNUTLS_X509_FMT_DER) ret = parse_der_cert_mem (&res->cert_list[res->ncerts], &res->cert_list_length[res->ncerts], cert, cert_size); else ret = parse_pem_cert_mem (&res->cert_list[res->ncerts], &res->cert_list_length[res->ncerts], cert, cert_size); if (ret < 0) { gnutls_assert (); return ret; } return ret; }
/** * gnutls_x509_trust_list_add_crls: * @list: The structure of the list * @crl_list: A list of CRLs * @crl_size: The length of the CRL list * @flags: if GNUTLS_TL_VERIFY_CRL is given the CRLs will be verified before being added. * @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 list of CRLs must not be deinitialized * during this structure's lifetime. * * This function must be called after gnutls_x509_trust_list_add_cas() * to allow verifying the CRLs for validity. * * Returns: The number of added elements is returned. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list, const gnutls_x509_crl_t * crl_list, int crl_size, unsigned int flags, unsigned int verification_flags) { int ret, i, j = 0; gnutls_datum_t dn; unsigned int vret = 0; uint32_t hash; /* 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++) { ret = gnutls_x509_crl_get_raw_issuer_dn(crl_list[i], &dn); if (ret < 0) { gnutls_assert(); return i; } hash = _gnutls_bhash(dn.data, dn.size, INIT_HASH); hash %= list->size; _gnutls_free_datum(&dn); 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) continue; } list->node[hash].crls = gnutls_realloc_fast(list->node[hash].crls, (list->node[hash].crl_size + 1) * sizeof(list->node[hash].trusted_cas[0])); if (list->node[hash].crls == NULL) { gnutls_assert(); return i; } list->node[hash].crls[list->node[hash].crl_size] = crl_list[i]; list->node[hash].crl_size++; j++; } return j; }
/* This function will set the auth info structure in the key * structure. * If allow change is !=0 then this will allow changing the auth * info structure to a different type. */ int _gnutls_auth_info_set (gnutls_session_t session, gnutls_credentials_type_t type, int size, int allow_change) { if (session->key->auth_info == NULL) { session->key->auth_info = gnutls_calloc (1, size); if (session->key->auth_info == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } session->key->auth_info_type = type; session->key->auth_info_size = size; } else { if (allow_change == 0) { /* If the credentials for the current authentication scheme, * are not the one we want to set, then it's an error. * This may happen if a rehandshake is performed an the * ciphersuite which is negotiated has different authentication * schema. */ if (gnutls_auth_get_type (session) != session->key->auth_info_type) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } } else { /* The new behaviour: Here we reallocate the auth info structure * in order to be able to negotiate different authentication * types. Ie. perform an auth_anon and then authenticate again using a * certificate (in order to prevent revealing the certificate's contents, * to passive eavesdropers. */ if (gnutls_auth_get_type (session) != session->key->auth_info_type) { session->key->auth_info = gnutls_realloc_fast (session->key->auth_info, size); if (session->key->auth_info == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } memset (session->key->auth_info, 0, size); session->key->auth_info_type = type; session->key->auth_info_size = size; } } } return 0; }
/** * gnutls_x509_trust_list_remove_cas: * @list: The structure of the list * @clist: A list of CAs * @clist_size: The length of the CA list * * This function will remove the given certificate authorities * from the trusted list. * * Note that this function can accept certificates and authorities * not yet known. In that case they will be kept in a separate * black list that will be used during certificate verification. * Unlike gnutls_x509_trust_list_add_cas() there is no deinitialization * restriction for certificate list provided in this function. * * Returns: The number of removed elements is returned. * * Since: 3.1.10 **/ int gnutls_x509_trust_list_remove_cas(gnutls_x509_trust_list_t list, const gnutls_x509_crt_t * clist, int clist_size) { int i, r = 0; unsigned j; uint32_t hash; for (i = 0; i < clist_size; i++) { hash = hash_pjw_bare(clist[i]->raw_dn.data, clist[i]->raw_dn.size); hash %= list->size; for (j = 0; j < list->node[hash].trusted_ca_size; j++) { if (_gnutls_check_if_same_cert (clist[i], list->node[hash].trusted_cas[j]) != 0) { gnutls_x509_crt_deinit(list->node[hash]. trusted_cas[j]); list->node[hash].trusted_cas[j] = list->node[hash].trusted_cas[list-> node [hash]. trusted_ca_size - 1]; list->node[hash].trusted_ca_size--; r++; break; } } /* Add the CA (or plain) certificate to the black list as well. * This will prevent a subordinate CA from being valid, and * ensure that a server certificate will also get rejected. */ list->blacklisted = gnutls_realloc_fast(list->blacklisted, (list->blacklisted_size + 1) * sizeof(list->blacklisted[0])); if (list->blacklisted == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); list->blacklisted[list->blacklisted_size] = crt_cpy(clist[i]); if (list->blacklisted[list->blacklisted_size] != NULL) list->blacklisted_size++; } return r; }
static int add_new_ca_to_rdn_seq(gnutls_x509_trust_list_t list, gnutls_x509_crt_t ca) { gnutls_datum_t tmp; size_t newsize; unsigned char *newdata, *p; /* Add DN of the last added CAs to the RDN sequence * This will be sent to clients when a certificate * request message is sent. */ /* FIXME: in case of a client it is not needed * to do that. This would save time and memory. * However we don't have that information available * here. * Further, this function is now much more efficient, * so optimizing that is less important. */ tmp.data = ca->raw_dn.data; tmp.size = ca->raw_dn.size; newsize = list->x509_rdn_sequence.size + 2 + tmp.size; if (newsize < list->x509_rdn_sequence.size) { gnutls_assert(); return GNUTLS_E_SHORT_MEMORY_BUFFER; } newdata = gnutls_realloc_fast(list->x509_rdn_sequence.data, newsize); if (newdata == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } p = newdata + list->x509_rdn_sequence.size; _gnutls_write_uint16(tmp.size, p); if (tmp.data != NULL) memcpy(p + 2, tmp.data, tmp.size); list->x509_rdn_sequence.size = newsize; list->x509_rdn_sequence.data = newdata; 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 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_fast(*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; }
int _gnutls_ext_register(extension_entry_st * mod) { extension_entry_st *p; p = gnutls_realloc_fast(extfunc, sizeof(*extfunc) * (extfunc_size + 1)); if (!p) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } extfunc = p; memcpy(&extfunc[extfunc_size], mod, sizeof(*mod)); extfunc_size++; return GNUTLS_E_SUCCESS; }
/* Keeps the provided certificate in a structure that will be * deallocated on deinit. This is to handle get_issuer() with * pkcs11 trust modules when the GNUTLS_TL_GET_COPY flag isn't * given. It is not thread safe. */ static int trust_list_add_compat(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert) { list->keep_certs = gnutls_realloc_fast(list->keep_certs, (list->keep_certs_size + 1) * sizeof(list->keep_certs[0])); if (list->keep_certs == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } list->keep_certs[list->keep_certs_size] = cert; list->keep_certs_size++; return 0; }
/** * gnutls_x509_trust_list_add_named_crt: * @list: The structure of the list * @cert: A certificate * @name: An identifier for the certificate * @name_size: The size of the identifier * @flags: should be 0. * * This function will add the given certificate to the trusted * list and associate it with a name. The certificate will not be * be used for verification with gnutls_x509_trust_list_verify_crt() * but only with gnutls_x509_trust_list_verify_named_crt(). * * In principle this function can be used to set individual "server" * certificates that are trusted by the user for that specific server * but for no other purposes. * * The certificate must not be deinitialized during the lifetime * of the trusted list. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_named_crt(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert, const void *name, size_t name_size, unsigned int flags) { gnutls_datum_t dn; int ret; uint32_t hash; if (name_size >= MAX_NAME_SIZE) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ret = gnutls_x509_crt_get_raw_issuer_dn(cert, &dn); if (ret < 0) { gnutls_assert(); return ret; } hash = _gnutls_bhash(dn.data, dn.size, INIT_HASH); hash %= list->size; _gnutls_free_datum(&dn); list->node[hash].named_certs = gnutls_realloc_fast(list->node[hash].named_certs, (list->node[hash].named_cert_size + 1) * sizeof(list->node[hash].named_certs[0])); if (list->node[hash].named_certs == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); list->node[hash].named_certs[list->node[hash].named_cert_size].cert = cert; memcpy(list->node[hash].named_certs[list->node[hash].named_cert_size]. name, name, name_size); list->node[hash].named_certs[list->node[hash].named_cert_size]. name_size = name_size; list->node[hash].named_cert_size++; return 0; }
/** * gnutls_x509_crl_list_import2: * @crls: The structures to store the parsed crl list. Must not be initialized. * @size: It will contain the size of the list. * @data: The PEM encoded CRL. * @format: One of DER or PEM. * @flags: must be (0) or an OR'd sequence of gnutls_certificate_import_flags. * * This function will convert the given PEM encoded CRL list * to the native gnutls_x509_crl_t format. The output will be stored * in @crls. They will be automatically initialized. * * If the Certificate is PEM encoded it should have a header of "X509 * CRL". * * Returns: the number of certificates read or a negative error value. * * Since: 3.0 **/ int gnutls_x509_crl_list_import2(gnutls_x509_crl_t ** crls, unsigned int *size, const gnutls_datum_t * data, gnutls_x509_crt_fmt_t format, unsigned int flags) { unsigned int init = 1024; int ret; *crls = gnutls_malloc(sizeof(gnutls_x509_crl_t) * init); if (*crls == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crl_list_import(*crls, &init, data, format, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { *crls = gnutls_realloc_fast(*crls, sizeof(gnutls_x509_crl_t) * init); if (*crls == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crl_list_import(*crls, &init, data, format, flags); } if (ret < 0) { gnutls_free(*crls); *crls = NULL; return ret; } *size = init; return 0; }
static int add_new_ca_to_rdn_seq(gnutls_x509_trust_list_t list, gnutls_x509_crt_t ca) { gnutls_datum_t tmp; size_t newsize; unsigned char *newdata, *p; /* Add DN of the last added CAs to the RDN sequence * This will be sent to clients when a certificate * request message is sent. */ tmp.data = ca->raw_dn.data; tmp.size = ca->raw_dn.size; newsize = list->x509_rdn_sequence.size + 2 + tmp.size; if (newsize < list->x509_rdn_sequence.size) { gnutls_assert(); return GNUTLS_E_SHORT_MEMORY_BUFFER; } newdata = gnutls_realloc_fast(list->x509_rdn_sequence.data, newsize); if (newdata == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } p = newdata + list->x509_rdn_sequence.size; _gnutls_write_uint16(tmp.size, p); if (tmp.data != NULL) memcpy(p + 2, tmp.data, tmp.size); list->x509_rdn_sequence.size = newsize; list->x509_rdn_sequence.data = newdata; return 0; }
/** * gnutls_x509_trust_list_add_cas: * @list: The structure of the list * @clist: A list of CAs * @clist_size: The length of the CA list * @flags: should be 0. * * This function will add the given certificate authorities * to the trusted list. The list of CAs must not be deinitialized * during this structure's lifetime. * * Returns: The number of added elements is returned. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list, const gnutls_x509_crt_t * clist, int clist_size, unsigned int flags) { gnutls_datum_t dn; int ret, i; uint32_t hash; for (i = 0; i < clist_size; i++) { ret = gnutls_x509_crt_get_raw_dn(clist[i], &dn); if (ret < 0) { gnutls_assert(); return i; } hash = _gnutls_bhash(dn.data, dn.size, INIT_HASH); hash %= list->size; _gnutls_free_datum(&dn); list->node[hash].trusted_cas = gnutls_realloc_fast(list->node[hash].trusted_cas, (list->node[hash].trusted_ca_size + 1) * sizeof(list->node[hash].trusted_cas[0])); if (list->node[hash].trusted_cas == NULL) { gnutls_assert(); return i; } list->node[hash].trusted_cas[list->node[hash].trusted_ca_size] = clist[i]; list->node[hash].trusted_ca_size++; } return i; }
/* Reads a PEM encoded PKCS-1 RSA/DSA private key from memory. Type * indicates the certificate format. KEY can be NULL, to indicate * that GnuTLS doesn't know the private key. */ static int read_key_mem (gnutls_certificate_credentials_t res, const void *key, int key_size, gnutls_x509_crt_fmt_t type) { int ret; gnutls_datum_t tmp; /* allocate space for the pkey list */ res->pkey = gnutls_realloc_fast (res->pkey, (res->ncerts + 1) * sizeof (gnutls_privkey)); if (res->pkey == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } if (key) { tmp.data = (opaque *) key; tmp.size = key_size; ret = _gnutls_x509_raw_privkey_to_gkey (&res->pkey[res->ncerts], &tmp, type); if (ret < 0) { gnutls_assert (); return ret; } } else memset (&res->pkey[res->ncerts], 0, sizeof (gnutls_privkey)); return 0; }
/** * gnutls_x509_trust_list_add_named_crt: * @list: The structure of the list * @cert: A certificate * @name: An identifier for the certificate * @name_size: The size of the identifier * @flags: should be 0. * * This function will add the given certificate to the trusted * list and associate it with a name. The certificate will not be * be used for verification with gnutls_x509_trust_list_verify_crt() * but with gnutls_x509_trust_list_verify_named_crt() or * gnutls_x509_trust_list_verify_crt2() - the latter only since * GnuTLS 3.4.0 and if a hostname is provided. * * In principle this function can be used to set individual "server" * certificates that are trusted by the user for that specific server * but for no other purposes. * * The certificate must not be deinitialized during the lifetime * of the trusted list. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_named_crt(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert, const void *name, size_t name_size, unsigned int flags) { uint32_t hash; if (name_size >= MAX_SERVER_NAME_SIZE) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); hash = hash_pjw_bare(cert->raw_issuer_dn.data, cert->raw_issuer_dn.size); hash %= list->size; list->node[hash].named_certs = gnutls_realloc_fast(list->node[hash].named_certs, (list->node[hash].named_cert_size + 1) * sizeof(list->node[hash].named_certs[0])); if (list->node[hash].named_certs == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); list->node[hash].named_certs[list->node[hash].named_cert_size]. cert = cert; memcpy(list->node[hash]. named_certs[list->node[hash].named_cert_size].name, name, name_size); list->node[hash].named_certs[list->node[hash]. named_cert_size].name_size = name_size; list->node[hash].named_cert_size++; return 0; }
static int gen_dhe_server_kx (gnutls_session_t session, opaque ** data) { bigint_t g, p; const bigint_t *mpis; int ret = 0, data_size; gnutls_cert *apr_cert_list; gnutls_privkey_t apr_pkey; int apr_cert_list_length; gnutls_datum_t signature = { NULL, 0 }, ddata; gnutls_certificate_credentials_t cred; gnutls_dh_params_t dh_params; gnutls_sign_algorithm_t sign_algo; gnutls_protocol_t ver = gnutls_protocol_get_version (session); cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } dh_params = _gnutls_get_dh_params (cred->dh_params, cred->params_func, session); mpis = _gnutls_dh_params_to_mpi (dh_params); if (mpis == NULL) { gnutls_assert (); return GNUTLS_E_NO_TEMPORARY_DH_PARAMS; } p = mpis[0]; g = mpis[1]; if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE, sizeof (cert_auth_info_st), 0)) < 0) { gnutls_assert (); return ret; } _gnutls_dh_set_group (session, g, p); ret = _gnutls_dh_common_print_server_kx (session, g, p, data, 0); if (ret < 0) { gnutls_assert (); return ret; } data_size = ret; /* Generate the signature. */ ddata.data = *data; ddata.size = data_size; if (apr_cert_list_length > 0) { if ((ret = _gnutls_handshake_sign_data (session, &apr_cert_list[0], apr_pkey, &ddata, &signature, &sign_algo)) < 0) { gnutls_assert (); goto cleanup; } } else { gnutls_assert (); ret = data_size; /* do not put a signature - ILLEGAL! */ goto cleanup; } *data = gnutls_realloc_fast (*data, data_size + signature.size + 4); if (*data == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } if (_gnutls_version_has_selectable_sighash (ver)) { const sign_algorithm_st *aid; if (sign_algo == GNUTLS_SIGN_UNKNOWN) { ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } aid = _gnutls_sign_to_tls_aid (sign_algo); if (aid == NULL) { gnutls_assert(); ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } (*data)[data_size++] = aid->hash_algorithm; (*data)[data_size++] = aid->sign_algorithm; } _gnutls_write_datum16 (&(*data)[data_size], signature); data_size += signature.size + 2; _gnutls_free_datum (&signature); return data_size; cleanup: _gnutls_free_datum (&signature); gnutls_free(*data); return ret; }
static int find_ext_cb(struct pkcs11_session_info *sinfo, struct token_info *info, struct ck_info *lib_info, void *input) { struct find_ext_data_st *find_data = input; struct ck_attribute a[4]; ck_object_class_t class = -1; unsigned long count; ck_rv_t rv; ck_object_handle_t obj; int ret; gnutls_datum_t ext; if (info == NULL) { /* we don't support multiple calls */ gnutls_assert(); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } /* do not bother reading the token if basic fields do not match */ if (!p11_kit_uri_match_token_info (find_data->obj->info, &info->tinfo) || !p11_kit_uri_match_module_info(find_data->obj->info, lib_info)) { gnutls_assert(); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } /* retrieve the extensions */ class = CKO_X_CERTIFICATE_EXTENSION; a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof class; a[1].type = CKA_PUBLIC_KEY_INFO; a[1].value = find_data->spki.data; a[1].value_len = find_data->spki.size; rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log ("p11: FindObjectsInit failed for cert extensions.\n"); return pkcs11_rv_to_err(rv); } while(pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1) { rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, obj, CKA_VALUE, &ext); if (rv == CKR_OK) { find_data->exts = gnutls_realloc_fast(find_data->exts, (1+find_data->exts_size)*sizeof(find_data->exts[0])); if (find_data->exts == NULL) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } if (_gnutls_x509_decode_ext(&ext, &find_data->exts[find_data->exts_size]) == 0) { find_data->exts_size++; } } } ret = 0; cleanup: pkcs11_find_objects_final(sinfo); return ret; }
/** * gnutls_pkcs12_simple_parse: * @p12: A pkcs12 type * @password: optional password used to decrypt the structure, bags and keys. * @key: a structure to store the parsed private key. * @chain: the corresponding to key certificate chain (may be %NULL) * @chain_len: will be updated with the number of additional (may be %NULL) * @extra_certs: optional pointer to receive an array of additional * certificates found in the PKCS12 structure (may be %NULL). * @extra_certs_len: will be updated with the number of additional * certs (may be %NULL). * @crl: an optional structure to store the parsed CRL (may be %NULL). * @flags: should be zero or one of GNUTLS_PKCS12_SP_* * * This function parses a PKCS12 structure in @pkcs12 and extracts the * private key, the corresponding certificate chain, any additional * certificates and a CRL. The structures in @key, @chain @crl, and @extra_certs * must not be initialized. * * The @extra_certs and @extra_certs_len parameters are optional * and both may be set to %NULL. If either is non-%NULL, then both must * be set. The value for @extra_certs is allocated * using gnutls_malloc(). * * Encrypted PKCS12 bags and PKCS8 private keys are supported, but * only with password based security and the same password for all * operations. * * Note that a PKCS12 structure may contain many keys and/or certificates, * and there is no way to identify which key/certificate pair you want. * For this reason this function is useful for PKCS12 files that contain * only one key/certificate pair and/or one CRL. * * If the provided structure has encrypted fields but no password * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED. * * Note that normally the chain constructed does not include self signed * certificates, to comply with TLS' requirements. If, however, the flag * %GNUTLS_PKCS12_SP_INCLUDE_SELF_SIGNED is specified then * self signed certificates will be included in the chain. * * Prior to using this function the PKCS #12 structure integrity must * be verified using gnutls_pkcs12_verify_mac(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1.0 **/ 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; uint8_t cert_id[20]; uint8_t key_id[20]; int privkey_ok = 0; unsigned int i; int elements_in_bag; *key = NULL; if (crl) *crl = NULL; /* find the first private key */ for (;;) { 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) { gnutls_pkcs12_bag_deinit(bag); bag = NULL; 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 < (unsigned)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; } FALLTHROUGH; 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(); 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(); goto done; } privkey_ok = 1; /* break */ break; default: break; } } idx++; gnutls_pkcs12_bag_deinit(bag); bag = NULL; 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 (;;) { 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) { gnutls_pkcs12_bag_deinit(bag); bag = NULL; 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 < (unsigned)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); this_cert = NULL; 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); this_cert = NULL; goto done; } if (memcmp(cert_id, key_id, cert_id_size) != 0) { /* they don't match - skip the certificate */ _extra_certs = gnutls_realloc_fast (_extra_certs, sizeof(_extra_certs [0]) * ++_extra_certs_len); if (!_extra_certs) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _extra_certs [_extra_certs_len - 1] = this_cert; this_cert = NULL; } else { if (chain && _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); this_cert = NULL; } } 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); *crl = NULL; 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); bag = NULL; } if (chain != NULL) { if (_chain_len != 1) { ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto done; } ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len, flags); 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); *key = NULL; } if (crl != NULL && *crl != NULL) { gnutls_x509_crl_deinit(*crl); *crl = NULL; } if (_extra_certs_len && _extra_certs != NULL) { for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (_chain_len && _chain != NULL) { for (i = 0; i < _chain_len; i++) gnutls_x509_crt_deinit(_chain[i]); gnutls_free(_chain); } return ret; } if (extra_certs && _extra_certs_len > 0) { *extra_certs = _extra_certs; *extra_certs_len = _extra_certs_len; } else { if (extra_certs) { *extra_certs = NULL; *extra_certs_len = 0; } for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (chain != NULL) { *chain = _chain; *chain_len = _chain_len; } return ret; }
/* Reads a base64 encoded certificate list from memory and stores it to * a gnutls_cert structure. Returns the number of certificate parsed. */ static int parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts, const char *input_cert, int input_cert_size) { int size, siz2, i; const char *ptr; opaque *ptr2; gnutls_datum_t tmp; int ret, count; /* move to the certificate */ ptr = memmem (input_cert, input_cert_size, PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1); if (ptr == NULL) ptr = memmem (input_cert, input_cert_size, PEM_CERT_SEP2, sizeof (PEM_CERT_SEP2) - 1); if (ptr == NULL) { gnutls_assert (); return GNUTLS_E_BASE64_DECODING_ERROR; } size = input_cert_size - (ptr - input_cert); i = *ncerts + 1; count = 0; do { siz2 = _gnutls_fbase64_decode (NULL, ptr, size, &ptr2); if (siz2 < 0) { gnutls_assert (); return GNUTLS_E_BASE64_DECODING_ERROR; } *cert_list = (gnutls_cert *) gnutls_realloc_fast (*cert_list, i * sizeof (gnutls_cert)); if (*cert_list == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } tmp.data = ptr2; tmp.size = siz2; ret = _gnutls_x509_raw_cert_to_gcert (&cert_list[0][i - 1], &tmp, 0); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_free_datum (&tmp); /* free ptr2 */ /* now we move ptr after the pem header */ ptr++; /* find the next certificate (if any) */ size = input_cert_size - (ptr - input_cert); if (size > 0) { char *ptr3; ptr3 = memmem (ptr, size, PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1); if (ptr3 == NULL) ptr3 = memmem (ptr, size, PEM_CERT_SEP2, sizeof (PEM_CERT_SEP2) - 1); ptr = ptr3; } else ptr = NULL; i++; count++; } while (ptr != NULL); *ncerts = i - 1; return count; }
/* * Return zero if session tickets haven't been enabled. */ int _gnutls_recv_new_session_ticket(gnutls_session_t session) { uint8_t *p; int data_size; gnutls_buffer_st buf; uint16_t ticket_len; int ret; session_ticket_ext_st *priv = NULL; gnutls_ext_priv_data_t epriv; if (session->internals.flags & GNUTLS_NO_TICKETS) return 0; if (!session->internals.session_ticket_renew) return 0; /* This is the last flight and peer cannot be sure * we have received it unless we notify him. So we * wait for a message and retransmit if needed. */ if (IS_DTLS(session) && !_dtls_is_async(session)) { unsigned have; mbuffer_st *bufel = NULL; have = gnutls_record_check_pending(session) + record_check_unprocessed(session); if (have != 0) { bufel = _mbuffer_head_get_first(&session->internals.record_buffer, NULL); } if (have == 0 || (bufel && bufel->type != GNUTLS_HANDSHAKE)) { ret = _dtls_wait_and_retransmit(session); if (ret < 0) return gnutls_assert_val(ret); } } ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, 0, &buf); if (ret < 0) return gnutls_assert_val_fatal(ret); p = buf.data; data_size = buf.length; DECR_LENGTH_COM(data_size, 4, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); /* skip over lifetime hint */ p += 4; DECR_LENGTH_COM(data_size, 2, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); ticket_len = _gnutls_read_uint16(p); p += 2; DECR_LENGTH_COM(data_size, ticket_len, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); priv = gnutls_calloc(1, sizeof(*priv)); if (!priv) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto error; } priv->session_ticket = gnutls_realloc_fast(priv->session_ticket, ticket_len); if (!priv->session_ticket) { gnutls_free(priv); gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto error; } memcpy(priv->session_ticket, p, ticket_len); priv->session_ticket_len = ticket_len; epriv = priv; /* Discard the current session ID. (RFC5077 3.4) */ ret = _gnutls_generate_session_id(session->security_parameters. session_id, &session->security_parameters. session_id_size); if (ret < 0) { gnutls_assert(); session_ticket_deinit_data(epriv); ret = GNUTLS_E_INTERNAL_ERROR; goto error; } ret = 0; _gnutls_handshake_log ("HSK[%p]: received session ticket\n", session); session->internals.hsk_flags |= HSK_TICKET_RECEIVED; _gnutls_hello_ext_set_priv(session, GNUTLS_EXTENSION_SESSION_TICKET, epriv); error: _gnutls_buffer_clear(&buf); return ret; }
int _gnutls_decompress (comp_hd_t handle, opaque * compressed, size_t compressed_size, opaque ** plain, size_t max_record_size) { int plain_size = GNUTLS_E_DECOMPRESSION_FAILED; if (compressed_size > max_record_size + EXTRA_COMP_SIZE) { gnutls_assert (); return GNUTLS_E_DECOMPRESSION_FAILED; } /* NULL compression is not handled here */ if (handle == NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } switch (handle->algo) { #ifdef USE_LZO case GNUTLS_COMP_LZO: { lzo_uint out_size; lzo_uint new_size; int err; if (_gnutls_lzo1x_decompress_safe == NULL) return GNUTLS_E_DECOMPRESSION_FAILED; *plain = NULL; out_size = compressed_size + compressed_size; plain_size = 0; do { out_size += 512; *plain = gnutls_realloc_fast (*plain, out_size); if (*plain == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } new_size = out_size; err = _gnutls_lzo1x_decompress_safe (compressed, compressed_size, *plain, &new_size, NULL); } while ((err == LZO_E_OUTPUT_OVERRUN && out_size < max_record_size)); if (err != LZO_E_OK) { gnutls_assert (); gnutls_free (*plain); *plain = NULL; return GNUTLS_E_DECOMPRESSION_FAILED; } plain_size = new_size; break; } #endif #ifdef HAVE_LIBZ case GNUTLS_COMP_DEFLATE: { uLongf out_size; z_stream *zhandle; int cur_pos; int err; *plain = NULL; out_size = compressed_size + compressed_size; plain_size = 0; zhandle = handle->handle; zhandle->next_in = (Bytef *) compressed; zhandle->avail_in = compressed_size; cur_pos = 0; do { out_size += 512; *plain = gnutls_realloc_fast (*plain, out_size); if (*plain == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } zhandle->next_out = (Bytef *) (*plain + cur_pos); zhandle->avail_out = out_size - cur_pos; err = inflate (zhandle, Z_SYNC_FLUSH); cur_pos = out_size - zhandle->avail_out; } while ((err == Z_BUF_ERROR && zhandle->avail_out == 0 && out_size < max_record_size) || (err == Z_OK && zhandle->avail_in != 0)); if (err != Z_OK) { gnutls_assert (); gnutls_free (*plain); *plain = NULL; return GNUTLS_E_DECOMPRESSION_FAILED; } plain_size = out_size - zhandle->avail_out; break; } #endif default: gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* switch */ if ((size_t) plain_size > max_record_size) { gnutls_assert (); gnutls_free (*plain); *plain = NULL; return GNUTLS_E_DECOMPRESSION_FAILED; } return plain_size; }
static int gen_srp_cert_server_kx (gnutls_session_t session, opaque ** data) { ssize_t ret, data_size; gnutls_datum_t signature, ddata; gnutls_certificate_credentials_t cred; gnutls_cert *apr_cert_list; gnutls_privkey_t apr_pkey; int apr_cert_list_length; gnutls_sign_algorithm_t sign_algo; ret = _gnutls_gen_srp_server_kx (session, data); if (ret < 0) return ret; data_size = ret; ddata.data = *data; ddata.size = data_size; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } if ((ret = _gnutls_handshake_sign_data (session, &apr_cert_list[0], apr_pkey, &ddata, &signature, &sign_algo)) < 0) { gnutls_assert (); gnutls_free (*data); return ret; } *data = gnutls_realloc_fast (*data, data_size + signature.size + 2); if (*data == NULL) { _gnutls_free_datum (&signature); gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_write_datum16 (&(*data)[data_size], signature); data_size += signature.size + 2; _gnutls_free_datum (&signature); return data_size; }
/* This function is like recv(with MSG_PEEK). But it does not return -1 on error. * It does return gnutls_errno instead. * This function reads data from the socket and keeps them in a buffer, of up to * MAX_RECV_SIZE. * * This is not a general purpose function. It returns EXACTLY the data requested, * which are stored in a local (in the session) buffer. A pointer (iptr) to this buffer is returned. * */ ssize_t _gnutls_io_read_buffered (gnutls_session_t session, opaque ** iptr, size_t sizeOfPtr, content_type_t recv_type) { ssize_t ret = 0, ret2 = 0; size_t min; int buf_pos; opaque *buf; int recvlowat; int recvdata, alloc_size; *iptr = session->internals.record_recv_buffer.data; if (sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0) { gnutls_assert (); /* internal error */ return GNUTLS_E_INVALID_REQUEST; } /* If an external pull function is used, then do not leave * any data into the kernel buffer. */ if (session->internals._gnutls_pull_func != NULL) { recvlowat = 0; } else { /* leave peeked data to the kernel space only if application data * is received and we don't have any peeked * data in gnutls session. */ if (recv_type != GNUTLS_APPLICATION_DATA && session->internals.have_peeked_data == 0) recvlowat = 0; else recvlowat = RCVLOWAT; } /* calculate the actual size, ie. get the minimum of the * buffered data and the requested data. */ min = MIN (session->internals.record_recv_buffer.length, sizeOfPtr); if (min > 0) { /* if we have enough buffered data * then just return them. */ if (min == sizeOfPtr) { return min; } } /* min is over zero. recvdata is the data we must * receive in order to return the requested data. */ recvdata = sizeOfPtr - min; /* Check if the previously read data plus the new data to * receive are longer than the maximum receive buffer size. */ if ((session->internals.record_recv_buffer.length + recvdata) > MAX_RECV_SIZE) { gnutls_assert (); /* internal error */ return GNUTLS_E_INVALID_REQUEST; } /* Allocate the data required to store the new packet. */ alloc_size = recvdata + session->internals.record_recv_buffer.length; session->internals.record_recv_buffer.data = gnutls_realloc_fast (session->internals.record_recv_buffer.data, alloc_size); if (session->internals.record_recv_buffer.data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } buf_pos = session->internals.record_recv_buffer.length; buf = session->internals.record_recv_buffer.data; *iptr = buf; /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer. */ if (recvdata - recvlowat > 0) { ret = _gnutls_read (session, &buf[buf_pos], recvdata - recvlowat, 0); /* return immediately if we got an interrupt or eagain * error. */ if (ret < 0 && gnutls_error_is_fatal (ret) == 0) { return ret; } } /* copy fresh data to our buffer. */ if (ret > 0) { _gnutls_read_log ("RB: Have %d bytes into buffer. Adding %d bytes.\n", session->internals.record_recv_buffer.length, ret); _gnutls_read_log ("RB: Requested %d bytes\n", sizeOfPtr); session->internals.record_recv_buffer.length += ret; } buf_pos = session->internals.record_recv_buffer.length; /* This is hack in order for select to work. Just leave recvlowat data, * into the kernel buffer (using a read with MSG_PEEK), thus making * select think, that the socket is ready for reading. * MSG_PEEK is only used with berkeley style sockets. */ if (ret == (recvdata - recvlowat) && recvlowat > 0) { ret2 = _gnutls_read (session, &buf[buf_pos], recvlowat, MSG_PEEK); if (ret2 < 0 && gnutls_error_is_fatal (ret2) == 0) { return ret2; } if (ret2 > 0) { _gnutls_read_log ("RB-PEEK: Read %d bytes in PEEK MODE.\n", ret2); _gnutls_read_log ("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n", session->internals.record_recv_buffer.length, ret2, sizeOfPtr); session->internals.have_peeked_data = 1; session->internals.record_recv_buffer.length += ret2; } } if (ret < 0 || ret2 < 0) { gnutls_assert (); /* that's because they are initialized to 0 */ return MIN (ret, ret2); } ret += ret2; if (ret > 0 && ret < recvlowat) { gnutls_assert (); return GNUTLS_E_AGAIN; } if (ret == 0) { /* EOF */ gnutls_assert (); return 0; } ret = session->internals.record_recv_buffer.length; if ((ret > 0) && ((size_t) ret < sizeOfPtr)) { /* Short Read */ gnutls_assert (); return GNUTLS_E_AGAIN; } else { return ret; } }
/** * gnutls_certificate_set_x509_key: * @res: is a #gnutls_certificate_credentials_t structure. * @cert_list: contains a certificate list (path) for the specified private key * @cert_list_size: holds the size of the certificate list * @key: is a gnutls_x509_privkey_t key * * This function sets a certificate/private key pair in the * gnutls_certificate_credentials_t structure. This function may be * called more than once (in case multiple keys/certificates exist for * the server). For clients that wants to send more than its own end * entity certificate (e.g., also an intermediate CA cert) then put * the certificate chain in @cert_list. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. * * Since: 2.4.0 **/ int gnutls_certificate_set_x509_key (gnutls_certificate_credentials_t res, gnutls_x509_crt_t * cert_list, int cert_list_size, gnutls_x509_privkey_t key) { int ret, i; /* this should be first */ res->pkey = gnutls_realloc_fast (res->pkey, (res->ncerts + 1) * sizeof (gnutls_privkey)); if (res->pkey == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_x509_privkey_to_gkey (&res->pkey[res->ncerts], key); if (ret < 0) { gnutls_assert (); return ret; } res->cert_list = gnutls_realloc_fast (res->cert_list, (1 + res->ncerts) * sizeof (gnutls_cert *)); if (res->cert_list == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } res->cert_list_length = gnutls_realloc_fast (res->cert_list_length, (1 + res->ncerts) * sizeof (int)); if (res->cert_list_length == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } res->cert_list[res->ncerts] = NULL; /* for realloc */ res->cert_list_length[res->ncerts] = 0; for (i = 0; i < cert_list_size; i++) { ret = parse_crt_mem (&res->cert_list[res->ncerts], &res->cert_list_length[res->ncerts], cert_list[i]); if (ret < 0) { gnutls_assert (); return ret; } } res->ncerts++; if ((ret = _gnutls_check_key_cert_match (res)) < 0) { gnutls_assert (); return ret; } return 0; }
static int gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data) { gnutls_rsa_params_t rsa_params; const bigint_t *rsa_mpis; size_t n_e, n_m; uint8_t *data_e, *data_m; int ret = 0, data_size; gnutls_cert *apr_cert_list; gnutls_privkey *apr_pkey; int apr_cert_list_length; gnutls_datum_t signature, ddata; cert_auth_info_t info; gnutls_certificate_credentials_t cred; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } /* abort sending this message if we have a certificate * of 512 bits or less. */ if (apr_pkey && _gnutls_mpi_get_nbits (apr_pkey->params[0]) <= 512) { gnutls_assert (); return GNUTLS_E_INT_RET_0; } rsa_params = _gnutls_certificate_get_rsa_params (cred->rsa_params, cred->params_func, session); rsa_mpis = _gnutls_rsa_params_to_mpi (rsa_params); if (rsa_mpis == NULL) { gnutls_assert (); return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS; } if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE, sizeof (cert_auth_info_st), 0)) < 0) { gnutls_assert (); return ret; } info = _gnutls_get_auth_info (session); _gnutls_rsa_export_set_pubkey (session, rsa_mpis[1], rsa_mpis[0]); _gnutls_mpi_print (rsa_mpis[0], NULL, &n_m); _gnutls_mpi_print (rsa_mpis[1], NULL, &n_e); (*data) = gnutls_malloc (n_e + n_m + 4); if (*data == NULL) { return GNUTLS_E_MEMORY_ERROR; } data_m = &(*data)[0]; _gnutls_mpi_print (rsa_mpis[0], &data_m[2], &n_m); _gnutls_write_uint16 (n_m, data_m); data_e = &data_m[2 + n_m]; _gnutls_mpi_print (rsa_mpis[1], &data_e[2], &n_e); _gnutls_write_uint16 (n_e, data_e); data_size = n_m + n_e + 4; /* Generate the signature. */ ddata.data = *data; ddata.size = data_size; if (apr_cert_list_length > 0) { if ((ret = _gnutls_tls_sign_params (session, &apr_cert_list[0], apr_pkey, &ddata, &signature)) < 0) { gnutls_assert (); gnutls_free (*data); *data = NULL; return ret; } } else { gnutls_assert (); return data_size; /* do not put a signature - ILLEGAL! */ } *data = gnutls_realloc_fast (*data, data_size + signature.size + 2); if (*data == NULL) { _gnutls_free_datum (&signature); gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_write_datum16 (&((*data)[data_size]), signature); data_size += signature.size + 2; _gnutls_free_datum (&signature); return data_size; }
/** * gnutls_certificate_set_openpgp_key - Used to set keys in a gnutls_certificate_credentials_t structure * @res: is a #gnutls_certificate_credentials_t structure. * @key: contains an openpgp public key * @pkey: is an openpgp private key * * This function sets a certificate/private key pair in the * gnutls_certificate_credentials_t structure. This function may be * called more than once (in case multiple keys/certificates exist * for the server). * * With this function the subkeys of the certificate are not used. * * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned, * otherwise an error code is returned. **/ int gnutls_certificate_set_openpgp_key (gnutls_certificate_credentials_t res, gnutls_openpgp_crt_t crt, gnutls_openpgp_privkey_t pkey) { int ret; /* this should be first */ res->pkey = gnutls_realloc_fast (res->pkey, (res->ncerts + 1) * sizeof (gnutls_privkey)); if (res->pkey == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_openpgp_privkey_to_gkey (&res->pkey[res->ncerts], pkey); if (ret < 0) { gnutls_assert (); return ret; } res->cert_list = gnutls_realloc_fast (res->cert_list, (1 + res->ncerts) * sizeof (gnutls_cert *)); if (res->cert_list == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } res->cert_list_length = gnutls_realloc_fast (res->cert_list_length, (1 + res->ncerts) * sizeof (int)); if (res->cert_list_length == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } res->cert_list[res->ncerts] = gnutls_calloc (1, sizeof (gnutls_cert)); if (res->cert_list[res->ncerts] == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } res->cert_list_length[res->ncerts] = 1; ret = _gnutls_openpgp_crt_to_gcert (res->cert_list[res->ncerts], crt); if (ret < 0) { gnutls_assert (); return ret; } res->ncerts++; /* FIXME: Check if the keys match. */ return 0; }
/** * gnutls_x509_trust_list_add_cas: * @list: The structure of the list * @clist: A list of CAs * @clist_size: The length of the CA list * @flags: should be 0 or an or'ed sequence of %GNUTLS_TL options. * * This function will add the given certificate authorities * to the trusted list. The list of CAs must not be deinitialized * during this structure's lifetime. * * If the flag %GNUTLS_TL_NO_DUPLICATES is specified, then * the provided @clist entries that are duplicates will not be * added to the list and will be deinitialized. * * Returns: The number of added elements is returned. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list, const gnutls_x509_crt_t * clist, unsigned clist_size, unsigned int flags) { unsigned i, j; uint32_t hash; int ret; unsigned exists; for (i = 0; i < clist_size; i++) { exists = 0; hash = hash_pjw_bare(clist[i]->raw_dn.data, clist[i]->raw_dn.size); hash %= list->size; /* avoid duplicates */ if (flags & GNUTLS_TL_NO_DUPLICATES || flags & GNUTLS_TL_NO_DUPLICATE_KEY) { for (j=0;j<list->node[hash].trusted_ca_size;j++) { if (flags & GNUTLS_TL_NO_DUPLICATES) ret = _gnutls_check_if_same_cert(list->node[hash].trusted_cas[j], clist[i]); else ret = _gnutls_check_if_same_key(list->node[hash].trusted_cas[j], clist[i], 1); if (ret != 0) { exists = 1; break; } } if (exists != 0) { gnutls_x509_crt_deinit(list->node[hash].trusted_cas[j]); list->node[hash].trusted_cas[j] = clist[i]; continue; } } list->node[hash].trusted_cas = gnutls_realloc_fast(list->node[hash].trusted_cas, (list->node[hash].trusted_ca_size + 1) * sizeof(list->node[hash]. trusted_cas[0])); if (list->node[hash].trusted_cas == NULL) { gnutls_assert(); return i; } if (gnutls_x509_crt_get_version(clist[i]) >= 3 && gnutls_x509_crt_get_ca_status(clist[i], NULL) <= 0) { gnutls_datum_t dn; gnutls_assert(); if (gnutls_x509_crt_get_dn2(clist[i], &dn) >= 0) { _gnutls_audit_log(NULL, "There was a non-CA certificate in the trusted list: %s.\n", dn.data); gnutls_free(dn.data); } } list->node[hash].trusted_cas[list->node[hash]. trusted_ca_size] = clist[i]; list->node[hash].trusted_ca_size++; if (flags & GNUTLS_TL_USE_IN_TLS) { ret = add_new_ca_to_rdn_seq(list, clist[i]); if (ret < 0) { gnutls_assert(); return i; } } } return i; }
int _gnutls_recv_new_session_ticket(gnutls_session_t session) { uint8_t *p; int data_size; gnutls_buffer_st buf; uint16_t ticket_len; int ret; session_ticket_ext_st *priv = NULL; extension_priv_data_t epriv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SESSION_TICKET, &epriv); if (ret < 0) { gnutls_assert(); return 0; } priv = epriv; if (!priv->session_ticket_renew) return 0; /* This is the last flight and peer cannot be sure * we have received it unless we notify him. So we * wait for a message and retransmit if needed. */ if (IS_DTLS(session) && !_dtls_is_async(session) && (gnutls_record_check_pending(session) + record_check_unprocessed(session)) == 0) { ret = _dtls_wait_and_retransmit(session); if (ret < 0) return gnutls_assert_val(ret); } ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, 0, &buf); if (ret < 0) return gnutls_assert_val_fatal(ret); p = buf.data; data_size = buf.length; DECR_LENGTH_COM(data_size, 4, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); /* skip over lifetime hint */ p += 4; DECR_LENGTH_COM(data_size, 2, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); ticket_len = _gnutls_read_uint16(p); p += 2; DECR_LENGTH_COM(data_size, ticket_len, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); priv->session_ticket = gnutls_realloc_fast(priv->session_ticket, ticket_len); if (!priv->session_ticket) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto error; } memcpy(priv->session_ticket, p, ticket_len); priv->session_ticket_len = ticket_len; /* Discard the current session ID. (RFC5077 3.4) */ ret = _gnutls_generate_session_id(session->security_parameters. session_id, &session->security_parameters. session_id_size); if (ret < 0) { gnutls_assert(); gnutls_free(priv->session_ticket); priv->session_ticket = NULL; ret = GNUTLS_E_INTERNAL_ERROR; goto error; } ret = 0; error: _gnutls_buffer_clear(&buf); return ret; }
/* This is a receive function for the gnutls handshake * protocol. Makes sure that we have received all data. */ ssize_t _gnutls_handshake_io_recv_int (gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype, void *iptr, size_t sizeOfPtr) { size_t left; ssize_t i; opaque *ptr; size_t dsize; ptr = iptr; left = sizeOfPtr; if (sizeOfPtr == 0 || iptr == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (session->internals.handshake_recv_buffer.length > 0) { /* if we have already received some data */ if (sizeOfPtr <= session->internals.handshake_recv_buffer.length) { /* if requested less data then return it. */ gnutls_assert (); memcpy (iptr, session->internals.handshake_recv_buffer.data, sizeOfPtr); session->internals.handshake_recv_buffer.length -= sizeOfPtr; memmove (session->internals.handshake_recv_buffer.data, &session->internals.handshake_recv_buffer. data[sizeOfPtr], session->internals.handshake_recv_buffer.length); return sizeOfPtr; } gnutls_assert (); memcpy (iptr, session->internals.handshake_recv_buffer.data, session->internals.handshake_recv_buffer.length); htype = session->internals.handshake_recv_buffer_htype; type = session->internals.handshake_recv_buffer_type; left -= session->internals.handshake_recv_buffer.length; session->internals.handshake_recv_buffer.length = 0; } while (left > 0) { dsize = sizeOfPtr - left; i = _gnutls_recv_int (session, type, htype, &ptr[dsize], left); if (i < 0) { if (dsize > 0 && (i == GNUTLS_E_INTERRUPTED || i == GNUTLS_E_AGAIN)) { gnutls_assert (); session->internals.handshake_recv_buffer.data = gnutls_realloc_fast (session->internals. handshake_recv_buffer.data, dsize); if (session->internals.handshake_recv_buffer.data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } memcpy (session->internals.handshake_recv_buffer.data, iptr, dsize); session->internals.handshake_recv_buffer_htype = htype; session->internals.handshake_recv_buffer_type = type; session->internals.handshake_recv_buffer.length = dsize; } else session->internals.handshake_recv_buffer.length = 0; gnutls_assert (); return i; } else { if (i == 0) break; /* EOF */ } left -= i; } session->internals.handshake_recv_buffer.length = 0; return sizeOfPtr - left; }