/** * gnutls_certificate_free_keys: * @sc: is a #gnutls_certificate_credentials_t structure. * * This function will delete all the keys and the certificates associated * with the given credentials. This function must not be called when a * TLS negotiation that uses the credentials is in progress. * **/ void gnutls_certificate_free_keys (gnutls_certificate_credentials_t sc) { unsigned i, j; for (i = 0; i < sc->ncerts; i++) { for (j = 0; j < sc->certs[i].cert_list_length; j++) { gnutls_pcert_deinit (&sc->certs[i].cert_list[j]); } gnutls_free (sc->certs[i].cert_list); _gnutls_str_array_clear (&sc->certs[i].names); } gnutls_free (sc->certs); sc->certs = NULL; for (i = 0; i < sc->ncerts; i++) { gnutls_privkey_deinit (sc->pkey[i]); } gnutls_free (sc->pkey); sc->pkey = NULL; sc->ncerts = 0; }
/* Returns the name of the certificate of a null name */ int _gnutls_get_x509_name(gnutls_x509_crt_t crt, gnutls_str_array_t * names) { size_t max_size; int i, ret = 0, ret2; char name[MAX_CN]; unsigned have_dns_name = 0; for (i = 0; !(ret < 0); i++) { max_size = sizeof(name); ret = gnutls_x509_crt_get_subject_alt_name(crt, i, name, &max_size, NULL); if (ret == GNUTLS_SAN_DNSNAME) { have_dns_name = 1; ret2 = _gnutls_str_array_append_idna(names, name, max_size); if (ret2 < 0) { _gnutls_str_array_clear(names); return gnutls_assert_val(ret2); } } } if (have_dns_name == 0) { max_size = sizeof(name); ret = gnutls_x509_crt_get_dn_by_oid(crt, OID_X520_COMMON_NAME, 0, 0, name, &max_size); if (ret >= 0) { ret = _gnutls_str_array_append_idna(names, name, max_size); if (ret < 0) { _gnutls_str_array_clear(names); return gnutls_assert_val(ret); } } } return 0; }
/** * gnutls_certificate_set_x509_key: * @res: is a #gnutls_certificate_credentials_t type. * @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 type. 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 their own end * entity certificate (e.g., also an intermediate CA cert) then put * the certificate chain in @cert_list. * * Note that the certificates and keys provided, can be safely deinitialized * after this function is called. * * If that function fails to load the @res type is at an undefined state, it must * not be reused to load other keys or certificates. * * Note that, this function by default returns zero on success and a negative value on error. * Since 3.5.6, when the flag %GNUTLS_CERTIFICATE_API_V2 is set using gnutls_certificate_set_flags() * it returns an index (greater or equal to zero). That index can be used to other functions to refer to the added key-pair. * * Returns: On success this functions returns zero, and otherwise a negative value on error (see above for modifying that behavior). * * 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; gnutls_privkey_t pkey; gnutls_pcert_st *pcerts = NULL; gnutls_str_array_t names; _gnutls_str_array_init(&names); /* this should be first */ ret = gnutls_privkey_init(&pkey); if (ret < 0) { gnutls_assert(); return ret; } if (res->pin.cb) gnutls_privkey_set_pin_function(pkey, res->pin.cb, res->pin.data); ret = gnutls_privkey_import_x509(pkey, key, GNUTLS_PRIVKEY_IMPORT_COPY); if (ret < 0) { gnutls_assert(); return ret; } /* load certificates */ pcerts = gnutls_malloc(sizeof(gnutls_pcert_st) * cert_list_size); if (pcerts == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_get_x509_name(cert_list[0], &names); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pcert_import_x509_list(pcerts, cert_list, (unsigned int*)&cert_list_size, GNUTLS_X509_CRT_LIST_SORT); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_certificate_credential_append_keypair(res, pkey, names, pcerts, cert_list_size); if (ret < 0) { gnutls_assert(); goto cleanup; } res->ncerts++; /* after this point we do not deinitialize anything on failure to avoid * double freeing. We intentionally keep everything as the credentials state * is documented to be on undefined state. */ if ((ret = _gnutls_check_key_cert_match(res)) < 0) { gnutls_assert(); return ret; } CRED_RET_SUCCESS(res); cleanup: gnutls_free(pcerts); _gnutls_str_array_clear(&names); return ret; }
/* Reads a certificate key from a token. */ static int read_cert_url(gnutls_certificate_credentials_t res, gnutls_privkey_t key, const char *url) { int ret; gnutls_x509_crt_t crt = NULL; gnutls_pcert_st *ccert = NULL; gnutls_str_array_t names; gnutls_datum_t t = {NULL, 0}; unsigned i, count = 0; _gnutls_str_array_init(&names); ccert = gnutls_malloc(sizeof(*ccert)*MAX_PKCS11_CERT_CHAIN); if (ccert == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } if (res->pin.cb) gnutls_x509_crt_set_pin_function(crt, res->pin.cb, res->pin.data); ret = gnutls_x509_crt_import_url(crt, url, 0); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ret = gnutls_x509_crt_import_url(crt, url, GNUTLS_PKCS11_OBJ_FLAG_LOGIN); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_get_x509_name(crt, &names); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Try to load the whole certificate chain from the PKCS #11 token */ for (i=0;i<MAX_PKCS11_CERT_CHAIN;i++) { ret = gnutls_x509_crt_check_issuer(crt, crt); if (i > 0 && ret != 0) { /* self signed */ break; } ret = gnutls_pcert_import_x509(&ccert[i], crt, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } count++; ret = _gnutls_get_raw_issuer(url, crt, &t, 0); if (ret < 0) break; gnutls_x509_crt_deinit(crt); crt = NULL; ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_x509_crt_import(crt, &t, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(t.data); } ret = _gnutls_certificate_credential_append_keypair(res, key, names, ccert, count); if (ret < 0) { gnutls_assert(); goto cleanup; } if (crt != NULL) gnutls_x509_crt_deinit(crt); return 0; cleanup: if (crt != NULL) gnutls_x509_crt_deinit(crt); gnutls_free(t.data); _gnutls_str_array_clear(&names); gnutls_free(ccert); 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_certificate_credentials_t res, gnutls_privkey_t key, const char *input_cert, int input_cert_size) { int size; const char *ptr; gnutls_datum_t tmp; int ret, count, i; unsigned ncerts = 0; gnutls_pcert_st *pcerts = NULL; gnutls_str_array_t names; gnutls_x509_crt_t unsorted[DEFAULT_MAX_VERIFY_DEPTH]; _gnutls_str_array_init(&names); /* 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); count = 0; do { tmp.data = (void *) ptr; tmp.size = size; ret = gnutls_x509_crt_init(&unsorted[count]); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_x509_crt_import(unsorted[count], &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) { gnutls_assert(); goto cleanup; } count++; /* now we move ptr after the pem header */ ptr++; size--; /* find the next certificate (if any) */ 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; size = input_cert_size - (ptr - input_cert); } else ptr = NULL; } while (ptr != NULL && count < DEFAULT_MAX_VERIFY_DEPTH); ret = _gnutls_get_x509_name(unsorted[0], &names); if (ret < 0) { gnutls_assert(); goto cleanup; } pcerts = gnutls_malloc(sizeof(gnutls_pcert_st) * count); if (pcerts == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ncerts = count; ret = gnutls_pcert_import_x509_list(pcerts, unsorted, &ncerts, GNUTLS_X509_CRT_LIST_SORT); if (ret < 0) { gnutls_free(pcerts); gnutls_assert(); goto cleanup; } ret = _gnutls_certificate_credential_append_keypair(res, key, names, pcerts, ncerts); if (ret < 0) { gnutls_assert(); goto cleanup; } for (i = 0; i < count; i++) gnutls_x509_crt_deinit(unsorted[i]); return ncerts; cleanup: _gnutls_str_array_clear(&names); for (i = 0; i < count; i++) gnutls_x509_crt_deinit(unsorted[i]); if (pcerts) { for (i = 0; i < count; i++) gnutls_pcert_deinit(&pcerts[i]); gnutls_free(pcerts); } return ret; }
/* 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_der_cert_mem(gnutls_certificate_credentials_t res, gnutls_privkey_t key, const void *input_cert, int input_cert_size) { gnutls_datum_t tmp; gnutls_x509_crt_t crt; gnutls_pcert_st *ccert; int ret; gnutls_str_array_t names; _gnutls_str_array_init(&names); ccert = gnutls_malloc(sizeof(*ccert)); if (ccert == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } tmp.data = (uint8_t *) input_cert; tmp.size = input_cert_size; ret = gnutls_x509_crt_import(crt, &tmp, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert(); gnutls_x509_crt_deinit(crt); goto cleanup; } ret = _gnutls_get_x509_name(crt, &names); if (ret < 0) { gnutls_assert(); gnutls_x509_crt_deinit(crt); goto cleanup; } ret = gnutls_pcert_import_x509(ccert, crt, 0); gnutls_x509_crt_deinit(crt); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_certificate_credential_append_keypair(res, key, names, ccert, 1); if (ret < 0) { gnutls_assert(); goto cleanup; } return ret; cleanup: _gnutls_str_array_clear(&names); gnutls_free(ccert); return ret; }