summaryrefslogtreecommitdiff
path: root/lib/cert-cred.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cert-cred.c')
-rw-r--r--lib/cert-cred.c197
1 files changed, 196 insertions, 1 deletions
diff --git a/lib/cert-cred.c b/lib/cert-cred.c
index 2d7009b2e5..f04ded4c04 100644
--- a/lib/cert-cred.c
+++ b/lib/cert-cred.c
@@ -40,7 +40,202 @@
#include <str_array.h>
#include <x509/verify-high.h>
#include "x509/x509_int.h"
+#include "x509/common.h"
#include "dh.h"
+#include "cert-cred.h"
+
+
+/*
+ * Adds a public/private key pair to a certificate credential
+ */
+int
+_gnutls_certificate_credential_append_keypair(gnutls_certificate_credentials_t res,
+ gnutls_privkey_t key,
+ gnutls_str_array_t names,
+ gnutls_pcert_st * crt,
+ int nr)
+{
+ res->sorted_cert_idx = gnutls_realloc_fast(res->sorted_cert_idx,
+ (1 + res->ncerts) *
+ sizeof(unsigned int));
+ if (res->sorted_cert_idx == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ res->certs = gnutls_realloc_fast(res->certs,
+ (1 + res->ncerts) *
+ sizeof(certs_st));
+ if (res->certs == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ memset(&res->certs[res->ncerts], 0, sizeof(res->certs[0]));
+
+ res->certs[res->ncerts].cert_list = crt;
+ res->certs[res->ncerts].cert_list_length = nr;
+ res->certs[res->ncerts].names = names;
+ res->certs[res->ncerts].pkey = key;
+
+ /* move RSA-PSS certificates before any RSA key.
+ * Note that we cannot assume that any previous pointers
+ * to sorted list are ok, due to the realloc in res->certs. */
+ if (crt->pubkey->params.algo == GNUTLS_PK_RSA_PSS) {
+ unsigned i,ridx;
+ unsigned tmp;
+
+ for (i=0;i<res->ncerts;i++) {
+ ridx = res->sorted_cert_idx[i];
+
+ if (res->certs[ridx].cert_list->pubkey->params.algo == GNUTLS_PK_RSA) {
+ tmp = ridx;
+ res->sorted_cert_idx[i] = res->ncerts;
+ res->sorted_cert_idx[res->ncerts] = tmp;
+ goto finish;
+ }
+ }
+ }
+
+ /* otherwise append it normally on the end */
+ res->sorted_cert_idx[res->ncerts] = res->ncerts;
+
+ finish:
+ return 0;
+
+}
+
+
+/**
+ * gnutls_certificate_set_key:
+ * @res: is a #gnutls_certificate_credentials_t type.
+ * @names: is an array of DNS names belonging to the public-key (NULL if none)
+ * @names_size: holds the size of the names list
+ * @pcert_list: contains a certificate list (chain) or raw public-key
+ * @pcert_list_size: holds the size of the certificate list
+ * @key: is a #gnutls_privkey_t key corresponding to the first public-key in pcert_list
+ *
+ * This function sets a public/private key pair in the
+ * gnutls_certificate_credentials_t type. The given public key may be encapsulated
+ * in a certificate or can be given as a raw key. This function may be
+ * called more than once, in case multiple key pairs exist for
+ * the server. For clients that want to send more than their own end-
+ * entity certificate (e.g., also an intermediate CA cert), the full
+ * certificate chain must be provided in @pcert_list.
+ *
+ * Note that the @key will become part of the credentials structure and must
+ * not be deallocated. It will be automatically deallocated when the @res structure
+ * is deinitialized.
+ *
+ * If this function fails, the @res structure is at an undefined state and 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 for other functions to refer to the added key-pair.
+ *
+ * Since GnuTLS 3.6.6 this function also handles raw public keys.
+ *
+ * Returns: On success this functions returns zero, and otherwise a negative value on error (see above for modifying that behavior).
+ *
+ * Since: 3.0
+ **/
+int
+gnutls_certificate_set_key(gnutls_certificate_credentials_t res,
+ const char **names,
+ int names_size,
+ gnutls_pcert_st * pcert_list,
+ int pcert_list_size,
+ gnutls_privkey_t key)
+{
+ int ret, i;
+ gnutls_str_array_t str_names;
+ gnutls_pcert_st *new_pcert_list;
+
+ /* Sanity checks */
+ // Check for a valid credential struct
+ if (res == NULL) {
+ return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ }
+
+ // A complete key pair must be given
+ if (pcert_list == NULL || key == NULL) {
+ return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
+ }
+
+ /* Process the names, if any */
+ _gnutls_str_array_init(&str_names);
+
+ if (names != NULL && names_size > 0) {
+ for (i = 0; i < names_size; i++) {
+ ret =
+ _gnutls_str_array_append_idna(&str_names, names[i],
+ strlen(names[i]));
+ if (ret < 0) {
+ ret = gnutls_assert_val(ret);
+ goto cleanup;
+ }
+ }
+ } else if (names == NULL && pcert_list[0].type == GNUTLS_CRT_X509) {
+ gnutls_x509_crt_t crt;
+
+ ret = gnutls_x509_crt_init(&crt);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = gnutls_x509_crt_import(crt, &pcert_list[0].cert, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ gnutls_assert();
+ gnutls_x509_crt_deinit(crt);
+ goto cleanup;
+ }
+
+ ret = _gnutls_get_x509_name(crt, &str_names);
+ gnutls_x509_crt_deinit(crt);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ if (res->pin.cb)
+ gnutls_privkey_set_pin_function(key, res->pin.cb,
+ res->pin.data);
+
+ new_pcert_list = gnutls_malloc(sizeof(gnutls_pcert_st) * pcert_list_size);
+ if (new_pcert_list == NULL) {
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+ memcpy(new_pcert_list, pcert_list, sizeof(gnutls_pcert_st) * pcert_list_size);
+
+ ret =
+ _gnutls_certificate_credential_append_keypair(res, key, str_names,
+ new_pcert_list,
+ pcert_list_size);
+ if (ret < 0) {
+ gnutls_assert();
+ gnutls_free(new_pcert_list);
+ goto cleanup;
+ }
+
+ res->ncerts++;
+
+ /* Unlike gnutls_certificate_set_x509_key, we deinitialize everything
+ * local after a failure. That is because the caller is responsible for
+ * freeing these values after a failure, and if we keep references we
+ * lead to double freeing */
+ if ((ret = _gnutls_check_key_cert_match(res)) < 0) {
+ gnutls_assert();
+ gnutls_free(new_pcert_list);
+ res->ncerts--;
+ goto cleanup;
+ }
+
+ CRED_RET_SUCCESS(res);
+
+ cleanup:
+ _gnutls_str_array_clear(&str_names);
+ return ret;
+}
/**
* gnutls_certificate_free_keys:
@@ -199,7 +394,7 @@ gnutls_certificate_free_credentials(gnutls_certificate_credentials_t sc)
// Check for valid pointer and otherwise do nothing
if (sc == NULL)
return;
-
+
gnutls_x509_trust_list_deinit(sc->tlist, 1);
gnutls_certificate_free_keys(sc);
memset(sc->pin_tmp, 0, sizeof(sc->pin_tmp));