Пример #1
0
/*!
 * Get binary key ID from a key (public or private).
 */
static int keyid_bin(gnutls_x509_privkey_t key, gnutls_pubkey_t pubkey, dnssec_binary_t *id)
{
	assert(key || pubkey);
	assert(id);

	// Flags can be used to enable SHA-2 since GnuTLS 3.4.7.

	int flags = 0;
	uint8_t *buffer = alloca(DNSSEC_KEYID_BINARY_SIZE);
	size_t size = DNSSEC_KEYID_SIZE;

	int r = key ? gnutls_x509_privkey_get_key_id(key, flags, buffer, &size)
	            : gnutls_pubkey_get_key_id(pubkey, flags, buffer, &size);

	if (r != GNUTLS_E_SUCCESS || size != DNSSEC_KEYID_BINARY_SIZE) {
		return DNSSEC_INVALID_KEY_ID;
	}

	assert(size == DNSSEC_KEYID_BINARY_SIZE);
	r = dnssec_binary_resize(id, size);
	if (r != DNSSEC_EOK) {
		return r;
	}

	memcpy(id->data, buffer, size);

	return DNSSEC_EOK;
}
Пример #2
0
/**
 * 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;
}
Пример #3
0
/**
 * gnutls_pkcs11_copy_x509_privkey:
 * @token_url: A PKCS #11 URL specifying a token
 * @key: A private key
 * @label: A name to be used for the stored data
 * @key_usage: One of GNUTLS_KEY_*
 * @flags: One of GNUTLS_PKCS11_OBJ_* flags
 *
 * This function will copy a private key into a PKCS #11 token specified by
 * a URL. It is highly recommended flags to contain %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE
 * unless there is a strong reason not to.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_pkcs11_copy_x509_privkey (const char *token_url,
                                 gnutls_x509_privkey_t key,
                                 const char *label,
                                 unsigned int key_usage, unsigned int flags)
{
    int ret;
    pakchois_session_t *pks;
    struct pkcs11_url_info info;
    ck_rv_t rv;
    size_t id_size;
    opaque id[20];
    struct ck_attribute a[16];
    ck_object_class_t class = CKO_PRIVATE_KEY;
    ck_object_handle_t obj;
    ck_key_type_t type;
    unsigned int tval = 1;
    int a_val;
    gnutls_pk_algorithm_t pk;
    gnutls_datum_t p, q, g, y, x;
    gnutls_datum_t m, e, d, u, exp1, exp2;


    ret = pkcs11_url_to_info (token_url, &info);
    if (ret < 0)
    {
        gnutls_assert ();
        return ret;
    }

    id_size = sizeof (id);
    ret = gnutls_x509_privkey_get_key_id (key, 0, id, &id_size);
    if (ret < 0)
    {
        gnutls_assert ();
        goto cleanup;
    }

    ret =
        pkcs11_open_session (&pks, &info,
                             SESSION_WRITE | pkcs11_obj_flags_to_int (flags));
    if (ret < 0)
    {
        gnutls_assert ();
        return ret;
    }

    /* FIXME: copy key usage flags */
    a_val = 0;
    a[a_val].type = CKA_CLASS;
    a[a_val].value = &class;
    a[a_val].value_len = sizeof (class);
    a_val++;

    a[a_val].type = CKA_ID;
    a[a_val].value = id;
    a[a_val].value_len = id_size;
    a_val++;

    a[a_val].type = CKA_KEY_TYPE;
    a[a_val].value = &type;
    a[a_val].value_len = sizeof (type);
    a_val++;

    a[a_val].type = CKA_TOKEN;
    a[a_val].value = &tval;
    a[a_val].value_len = sizeof (tval);
    a_val++;

    a[a_val].type = CKA_PRIVATE;
    a[a_val].value = &tval;
    a[a_val].value_len = sizeof (tval);
    a_val++;

    if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE)
        tval = 1;
    else
        tval = 0;

    a[a_val].type = CKA_SENSITIVE;
    a[a_val].value = &tval;
    a[a_val].value_len = sizeof (tval);
    a_val++;

    pk = gnutls_x509_privkey_get_pk_algorithm (key);
    switch (pk)
    {
    case GNUTLS_PK_RSA:
    {

        ret =
            gnutls_x509_privkey_export_rsa_raw2 (key, &m,
                    &e, &d, &p,
                    &q, &u, &exp1, &exp2);
        if (ret < 0)
        {
            gnutls_assert ();
            goto cleanup;
        }

        type = CKK_RSA;

        a[a_val].type = CKA_MODULUS;
        a[a_val].value = m.data;
        a[a_val].value_len = m.size;
        a_val++;

        a[a_val].type = CKA_PUBLIC_EXPONENT;
        a[a_val].value = e.data;
        a[a_val].value_len = e.size;
        a_val++;

        a[a_val].type = CKA_PRIVATE_EXPONENT;
        a[a_val].value = d.data;
        a[a_val].value_len = d.size;
        a_val++;

        a[a_val].type = CKA_PRIME_1;
        a[a_val].value = p.data;
        a[a_val].value_len = p.size;
        a_val++;

        a[a_val].type = CKA_PRIME_2;
        a[a_val].value = q.data;
        a[a_val].value_len = q.size;
        a_val++;

        a[a_val].type = CKA_COEFFICIENT;
        a[a_val].value = u.data;
        a[a_val].value_len = u.size;
        a_val++;

        a[a_val].type = CKA_EXPONENT_1;
        a[a_val].value = exp1.data;
        a[a_val].value_len = exp1.size;
        a_val++;

        a[a_val].type = CKA_EXPONENT_2;
        a[a_val].value = exp2.data;
        a[a_val].value_len = exp2.size;
        a_val++;

        break;
    }
    case GNUTLS_PK_DSA:
    {
        ret = gnutls_x509_privkey_export_dsa_raw (key, &p, &q, &g, &y, &x);
        if (ret < 0)
        {
            gnutls_assert ();
            goto cleanup;
        }

        type = CKK_DSA;

        a[a_val].type = CKA_PRIME;
        a[a_val].value = p.data;
        a[a_val].value_len = p.size;
        a_val++;

        a[a_val].type = CKA_SUBPRIME;
        a[a_val].value = q.data;
        a[a_val].value_len = q.size;
        a_val++;

        a[a_val].type = CKA_BASE;
        a[a_val].value = g.data;
        a[a_val].value_len = g.size;
        a_val++;

        a[a_val].type = CKA_VALUE;
        a[a_val].value = x.data;
        a[a_val].value_len = x.size;
        a_val++;

        break;
    }
    default:
        gnutls_assert ();
        ret = GNUTLS_E_INVALID_REQUEST;
        goto cleanup;
    }

    rv = pakchois_create_object (pks, a, a_val, &obj);
    if (rv != CKR_OK)
    {
        gnutls_assert ();
        _gnutls_debug_log ("pkcs11: %s\n", pakchois_error (rv));
        ret = pkcs11_rv_to_err (rv);
        goto cleanup;
    }

    /* generated!
     */

    switch (pk)
    {
    case GNUTLS_PK_RSA:
    {
        gnutls_free (m.data);
        gnutls_free (e.data);
        gnutls_free (d.data);
        gnutls_free (p.data);
        gnutls_free (q.data);
        gnutls_free (u.data);
        gnutls_free (exp1.data);
        gnutls_free (exp2.data);
        break;
    }
    case GNUTLS_PK_DSA:
    {
        gnutls_free (p.data);
        gnutls_free (q.data);
        gnutls_free (g.data);
        gnutls_free (y.data);
        gnutls_free (x.data);
        break;
    }
    default:
        gnutls_assert ();
        ret = GNUTLS_E_INVALID_REQUEST;
        goto cleanup;
    }

    ret = 0;

cleanup:
    pakchois_close_session (pks);

    return ret;

}
Пример #4
0
/**
 * gnutls_pkcs11_copy_x509_privkey2:
 * @token_url: A PKCS #11 URL specifying a token
 * @key: A private key
 * @label: A name to be used for the stored data
 * @cid: The CKA_ID to set for the object -if NULL, the ID will be derived from the public key
 * @key_usage: One of GNUTLS_KEY_*
 * @flags: One of GNUTLS_PKCS11_OBJ_* flags
 *
 * This function will copy a private key into a PKCS #11 token specified by
 * a URL. It is highly recommended flags to contain %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE
 * unless there is a strong reason not to.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.4.0
 **/
int
gnutls_pkcs11_copy_x509_privkey2(const char *token_url,
				gnutls_x509_privkey_t key,
				const char *label,
				const gnutls_datum_t *cid,
				unsigned int key_usage, unsigned int flags)
{
	int ret;
	struct p11_kit_uri *info = NULL;
	ck_rv_t rv;
	size_t id_size;
	uint8_t id[20];
	struct ck_attribute a[32];
	ck_object_class_t class = CKO_PRIVATE_KEY;
	ck_object_handle_t ctx;
	ck_key_type_t type;
	int a_val;
	gnutls_pk_algorithm_t pk;
	gnutls_datum_t p, q, g, y, x;
	gnutls_datum_t m, e, d, u, exp1, exp2;
	struct pkcs11_session_info sinfo;

	PKCS11_CHECK_INIT;

	memset(&p, 0, sizeof(p));
	memset(&q, 0, sizeof(q));
	memset(&g, 0, sizeof(g));
	memset(&y, 0, sizeof(y));
	memset(&x, 0, sizeof(x));
	memset(&m, 0, sizeof(m));
	memset(&e, 0, sizeof(e));
	memset(&d, 0, sizeof(d));
	memset(&u, 0, sizeof(u));
	memset(&exp1, 0, sizeof(exp1));
	memset(&exp2, 0, sizeof(exp2));

	ret = pkcs11_url_to_info(token_url, &info, 0);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	ret =
	    pkcs11_open_session(&sinfo, NULL, info,
				SESSION_WRITE |
				pkcs11_obj_flags_to_int(flags));
	p11_kit_uri_free(info);

	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	pk = gnutls_x509_privkey_get_pk_algorithm(key);
	FIX_KEY_USAGE(pk, key_usage);

	/* FIXME: copy key usage flags */
	a_val = 0;
	a[a_val].type = CKA_CLASS;
	a[a_val].value = &class;
	a[a_val].value_len = sizeof(class);
	a_val++;

	a[a_val].type = CKA_ID;
	if (cid == NULL || cid->size == 0) {
		id_size = sizeof(id);
		ret = gnutls_x509_privkey_get_key_id(key, 0, id, &id_size);
		if (ret < 0) {
			p11_kit_uri_free(info);
			gnutls_assert();
			return ret;
		}

		a[a_val].value = id;
		a[a_val].value_len = id_size;
	} else {
		a[a_val].value = cid->data;
		a[a_val].value_len = cid->size;
	}
	a_val++;

	a[a_val].type = CKA_SIGN;
	if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) {
		a[a_val].value = (void*)&tval;
		a[a_val].value_len = sizeof(tval);
	} else {
		a[a_val].value = (void*)&fval;
		a[a_val].value_len = sizeof(fval);
	}
	a_val++;

	if (pk == GNUTLS_PK_RSA) {
		a[a_val].type = CKA_DECRYPT;
		if (key_usage & (GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_DECIPHER_ONLY)) {
			a[a_val].value = (void*)&tval;
			a[a_val].value_len = sizeof(tval);
		} else {
			a[a_val].value = (void*)&fval;
			a[a_val].value_len = sizeof(fval);
		}
		a_val++;
	}

	a[a_val].type = CKA_TOKEN;
	a[a_val].value = (void *) &tval;
	a[a_val].value_len = sizeof(tval);
	a_val++;

	/* a private key is set always as private unless
	 * requested otherwise
	 */
	if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) {
		a[a_val].type = CKA_PRIVATE;
		a[a_val].value = (void *) &fval;
		a[a_val].value_len = sizeof(fval);
		a_val++;
	} else {
		a[a_val].type = CKA_PRIVATE;
		a[a_val].value = (void *) &tval;
		a[a_val].value_len = sizeof(tval);
		a_val++;
	}

	if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH) {
		a[a_val].type = CKA_ALWAYS_AUTHENTICATE;
		a[a_val].value = (void *) &tval;
		a[a_val].value_len = sizeof(tval);
		a_val++;
	}

	if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_EXTRACTABLE) {
		a[a_val].type = CKA_EXTRACTABLE;
		a[a_val].value = (void *) &tval;
		a[a_val].value_len = sizeof(tval);
		(a_val)++;
	} else {
		a[a_val].type = CKA_EXTRACTABLE;
		a[a_val].value = (void *) &fval;
		a[a_val].value_len = sizeof(fval);
		(a_val)++;
	}

	if (label) {
		a[a_val].type = CKA_LABEL;
		a[a_val].value = (void *) label;
		a[a_val].value_len = strlen(label);
		a_val++;
	}

	if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) {
		a[a_val].type = CKA_SENSITIVE;
		a[a_val].value = (void *) &tval;
		a[a_val].value_len = sizeof(tval);
		a_val++;
	} else {
		a[a_val].type = CKA_SENSITIVE;
		a[a_val].value = (void *) &fval;
		a[a_val].value_len = sizeof(fval);
		a_val++;
	}

	switch (pk) {
	case GNUTLS_PK_RSA:
		{

			ret =
			    gnutls_x509_privkey_export_rsa_raw2(key, &m,
								&e, &d, &p,
								&q, &u,
								&exp1,
								&exp2);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}

			type = CKK_RSA;

			skip_leading_zeros(&m);
			skip_leading_zeros(&e);
			skip_leading_zeros(&d);
			skip_leading_zeros(&p);
			skip_leading_zeros(&q);
			skip_leading_zeros(&u);
			skip_leading_zeros(&exp1);
			skip_leading_zeros(&exp2);

			a[a_val].type = CKA_MODULUS;
			a[a_val].value = m.data;
			a[a_val].value_len = m.size;
			a_val++;

			a[a_val].type = CKA_PUBLIC_EXPONENT;
			a[a_val].value = e.data;
			a[a_val].value_len = e.size;
			a_val++;

			a[a_val].type = CKA_PRIVATE_EXPONENT;
			a[a_val].value = d.data;
			a[a_val].value_len = d.size;
			a_val++;

			a[a_val].type = CKA_PRIME_1;
			a[a_val].value = p.data;
			a[a_val].value_len = p.size;
			a_val++;

			a[a_val].type = CKA_PRIME_2;
			a[a_val].value = q.data;
			a[a_val].value_len = q.size;
			a_val++;

			a[a_val].type = CKA_COEFFICIENT;
			a[a_val].value = u.data;
			a[a_val].value_len = u.size;
			a_val++;

			a[a_val].type = CKA_EXPONENT_1;
			a[a_val].value = exp1.data;
			a[a_val].value_len = exp1.size;
			a_val++;

			a[a_val].type = CKA_EXPONENT_2;
			a[a_val].value = exp2.data;
			a[a_val].value_len = exp2.size;
			a_val++;

			break;
		}
	case GNUTLS_PK_DSA:
		{
			ret =
			    gnutls_x509_privkey_export_dsa_raw(key, &p, &q,
							       &g, &y, &x);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}

			type = CKK_DSA;

			skip_leading_zeros(&p);
			skip_leading_zeros(&q);
			skip_leading_zeros(&g);
			skip_leading_zeros(&y);
			skip_leading_zeros(&x);

			a[a_val].type = CKA_PRIME;
			a[a_val].value = p.data;
			a[a_val].value_len = p.size;
			a_val++;

			a[a_val].type = CKA_SUBPRIME;
			a[a_val].value = q.data;
			a[a_val].value_len = q.size;
			a_val++;

			a[a_val].type = CKA_BASE;
			a[a_val].value = g.data;
			a[a_val].value_len = g.size;
			a_val++;

			a[a_val].type = CKA_VALUE;
			a[a_val].value = x.data;
			a[a_val].value_len = x.size;
			a_val++;

			break;
		}
	case GNUTLS_PK_EC:
		{
			ret =
			    _gnutls_x509_write_ecc_params(key->params.flags,
							  &p);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}

			ret =
			    _gnutls_mpi_dprint(key->params.
						params[ECC_K], &x);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}

			type = CKK_ECDSA;

			a[a_val].type = CKA_EC_PARAMS;
			a[a_val].value = p.data;
			a[a_val].value_len = p.size;
			a_val++;

			a[a_val].type = CKA_VALUE;
			a[a_val].value = x.data;
			a[a_val].value_len = x.size;
			a_val++;

			break;
		}
	default:
		gnutls_assert();
		ret = GNUTLS_E_INVALID_REQUEST;
		goto cleanup;
	}

	a[a_val].type = CKA_KEY_TYPE;
	a[a_val].value = &type;
	a[a_val].value_len = sizeof(type);
	a_val++;

	rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &ctx);
	if (rv != CKR_OK) {
		gnutls_assert();
		_gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv));
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}

	ret = 0;

      cleanup:
	switch (pk) {
	case GNUTLS_PK_RSA:
		{
			gnutls_free(m.data);
			gnutls_free(e.data);
			gnutls_free(d.data);
			gnutls_free(p.data);
			gnutls_free(q.data);
			gnutls_free(u.data);
			gnutls_free(exp1.data);
			gnutls_free(exp2.data);
			break;
		}
	case GNUTLS_PK_DSA:
		{
			gnutls_free(p.data);
			gnutls_free(q.data);
			gnutls_free(g.data);
			gnutls_free(y.data);
			gnutls_free(x.data);
			break;
		}
	case GNUTLS_PK_EC:
		{
			gnutls_free(p.data);
			gnutls_free(x.data);
			break;
		}
	default:
		gnutls_assert();
		ret = GNUTLS_E_INVALID_REQUEST;
		break;
	}

	if (sinfo.pks != 0)
		pkcs11_close_session(&sinfo);

	return ret;

}
Пример #5
0
void
doit (void)
{
  gnutls_x509_privkey_t pkey;
  gnutls_privkey_t abs_pkey;
  gnutls_x509_crq_t crq;

  size_t pkey_key_id_len;
  unsigned char *pkey_key_id = NULL;

  size_t crq_key_id_len;
  unsigned char *crq_key_id = NULL;

  gnutls_pk_algorithm_t algorithm;

  int ret;

  ret = global_init ();
  if (ret < 0)
    fail ("global_init: %d\n", ret);

  gnutls_global_set_log_function (tls_log_func);
  if (debug)
    gnutls_global_set_log_level (4711);

  for (algorithm = GNUTLS_PK_RSA; algorithm <= GNUTLS_PK_DSA; algorithm++)
    {
      ret = gnutls_x509_crq_init (&crq);
      if (ret < 0)
        fail ("gnutls_x509_crq_init: %d\n", ret);

      ret = gnutls_x509_privkey_init (&pkey);
      if (ret < 0)
        {
          fail ("gnutls_x509_privkey_init: %d\n", ret);
        }

      ret = gnutls_privkey_init (&abs_pkey);
      if (ret < 0)
        {
          fail ("gnutls_privkey_init: %d\n", ret);
        }

      ret = gnutls_x509_privkey_generate (pkey, algorithm, 1024, 0);
      if (ret < 0)
        {
          fail ("gnutls_x509_privkey_generate (rsa): %d\n", ret);
        }
      else if (debug)
        {
          success ("Key[%s] generation ok: %d\n",
                   gnutls_pk_algorithm_get_name (algorithm), ret);
        }

      pkey_key_id_len = 0;
      ret = gnutls_x509_privkey_get_key_id (pkey, 0, pkey_key_id,
                                            &pkey_key_id_len);
      if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
        {
          fail ("gnutls_x509_privkey_get_key_id incorrectly returns %d\n",
                ret);
        }

      pkey_key_id = malloc (sizeof (unsigned char) * pkey_key_id_len);
      ret = gnutls_x509_privkey_get_key_id (pkey, 0, pkey_key_id,
                                            &pkey_key_id_len);
      if (ret != GNUTLS_E_SUCCESS)
        {
          fail ("gnutls_x509_privkey_get_key_id incorrectly returns %d\n",
                ret);
        }

      ret = gnutls_x509_crq_set_version (crq, 1);
      if (ret < 0)
        {
          fail ("gnutls_x509_crq_set_version: %d\n", ret);
        }

      ret = gnutls_x509_crq_set_key (crq, pkey);
      if (ret < 0)
        {
          fail ("gnutls_x509_crq_set_key: %d\n", ret);
        }

      ret = gnutls_x509_crq_set_dn_by_oid (crq, GNUTLS_OID_X520_COMMON_NAME,
                                           0, "CN-Test", 7);
      if (ret < 0)
        {
          fail ("gnutls_x509_crq_set_dn_by_oid: %d\n", ret);
        }

      ret = gnutls_privkey_import_x509( abs_pkey, pkey, 0);
      if (ret < 0)
        {
          fail ("gnutls_privkey_import_x509: %d\n", ret);
        }

      ret = gnutls_x509_crq_privkey_sign (crq, abs_pkey, GNUTLS_DIG_SHA1, 0);
      if (ret < 0)
        {
          fail ("gnutls_x509_crq_sign: %d\n", ret);
        }

      ret = gnutls_x509_crq_verify (crq, 0);
      if (ret < 0)
        {
          fail ("gnutls_x509_crq_verify: %d\n", ret);
        }

      crq_key_id_len = 0;
      ret = gnutls_x509_crq_get_key_id (crq, 0, crq_key_id, &crq_key_id_len);
      if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
        {
          fail ("gnutls_x509_crq_get_key_id incorrectly returns %d\n", ret);
        }

      crq_key_id = malloc (sizeof (unsigned char) * crq_key_id_len);
      ret = gnutls_x509_crq_get_key_id (crq, 0, crq_key_id, &crq_key_id_len);
      if (ret != GNUTLS_E_SUCCESS)
        {
          fail ("gnutls_x509_crq_get_key_id incorrectly returns %d\n", ret);
        }

      if (crq_key_id_len == pkey_key_id_len)
        {
          ret = memcmp (crq_key_id, pkey_key_id, crq_key_id_len);
          if (ret == 0)
            {
              if (debug)
                success ("Key ids are identical. OK.\n");
            }
          else
            {
              fail ("Key ids differ incorrectly: %d\n", ret);
            }
        }
      else
        {
          fail ("Key_id lengths differ incorrectly: %d - %d\n",
                (int) crq_key_id_len, (int) pkey_key_id_len);
        }


      if (pkey_key_id)
        {
          free (pkey_key_id);
          pkey_key_id = NULL;
        }

      if (crq_key_id)
        {
          free (crq_key_id);
          crq_key_id = NULL;
        }

      gnutls_x509_crq_deinit (crq);
      gnutls_x509_privkey_deinit (pkey);
      gnutls_privkey_deinit (abs_pkey);
    }

  gnutls_global_deinit ();
}
Пример #6
0
bool load_p12(gnutls_certificate_credentials_t xcred,
				  const char *const p12_file,
				  const char *const password)
{
	FILE*p12file;
	gnutls_datum_t p12blob;
	gnutls_pkcs12_t p12 = NULL;

	gnutls_x509_privkey_t key = NULL;
	gnutls_x509_crt_t certs[MAX_CERTS];
	int certs_nr;
	int id_cert;

	uint8_t key_id[20];
	size_t key_id_size;

	bool is_success = false;
	int ret;
	int i;

	assert(p12_file != NULL);

	/* Read file */
	p12file = fopen(p12_file, "rb");
	if(p12file == NULL)
	{
		trace(LOG_ERR, "failed to open PKCS#12 file '%s': %s (%d)", p12_file,
				strerror(errno), errno);
		ret = GNUTLS_E_FILE_ERROR;
		goto error;
	}
	p12blob.data = malloc(32768 * sizeof(char));
	p12blob.size = fread((void*) p12blob.data, sizeof(char), 32768, p12file);
	fclose(p12file);

	/* Init structure and import P12 */
	ret = gnutls_pkcs12_init(&p12);
	if(ret < 0)
	{
		trace(LOG_ERR, "failed to init PKCS#12 object (%d)", ret);
		goto free_blob;
	}

	ret = gnutls_pkcs12_import(p12, &p12blob, GNUTLS_X509_FMT_DER, 0);
	if(ret < 0)
	{
		trace(LOG_ERR, "failed to import PKCS#12 data (%d)", ret);
		goto deinit_pkcs12;
	}

	if(password)
	{
		ret = gnutls_pkcs12_verify_mac(p12, password);
		if(ret < 0)
		{
			trace(LOG_ERR, "failed to verify PKCS#12 MAC (%d)", ret);
			goto deinit_pkcs12;
		}
	}

	/* extract the private key and the certificates from PKCS#12 */
	if(!tls_parse_pkcs12(&p12, password, &key, certs, &certs_nr))
	{
		trace(LOG_ERR, "failed to parse PKCS#12 file '%s'", p12_file);
		goto deinit_pkcs12;
	}
	if(certs_nr < 2)
	{
		trace(LOG_ERR, "too few certificates in PKCS#12 file '%s'", p12_file);
		goto free_certs_key;
	}
	
	/* get the ID of private key */
	key_id_size = sizeof(key_id);
	ret = gnutls_x509_privkey_get_key_id(key, 0, key_id, &key_id_size);
	if(ret < 0)
	{
		trace(LOG_ERR, "failed to get key ID");
		goto free_certs_key;
	}

	id_cert = -1;
	for(i = 0; i < certs_nr; i++)
	{
		uint8_t cert_id[20];
		size_t cert_id_size;

		cert_id_size = sizeof(cert_id);
		ret = gnutls_x509_crt_get_key_id(certs[i], 0, cert_id, &cert_id_size);
		if(ret < 0)
		{
			trace(LOG_ERR, "failed to get key ID for certificate #%d (%d)", i, ret);
			goto free_certs_key;
		}

		if(key_id_size == cert_id_size &&
			memcmp(cert_id, key_id, cert_id_size) == 0)
		{
			/* it's the key certificate ! */
			if(id_cert != -1)
			{
				ret = GNUTLS_E_INTERRUPTED;
				trace(LOG_ERR, "Duplicate key certificate !\n");
				goto free_certs_key;
			}
			id_cert = i;
		}
	}

	if(id_cert == -1)
	{
		ret = GNUTLS_E_INTERRUPTED;
		trace(LOG_ERR, "Unable to find key certificate !\n");
		goto free_certs_key;
	}

	/* Now have fun with the key and certs ! */
	ret = gnutls_certificate_set_x509_key(xcred, &certs[id_cert], 1, key);
	if(ret < 0)
	{
		trace(LOG_ERR, "failed to set key for main certificate");
		goto free_certs_key;
	}

	for(i = 0; i < certs_nr; i++)
	{
		if(i != id_cert)
		{
			ret = gnutls_certificate_set_x509_trust(xcred, &certs[i], 1);
			if(ret < 0)
			{
				trace(LOG_ERR, "failed to trust certificate #%d", i + 1);
				goto free_certs_key;
			}
		}
	}

	is_success = true;

free_certs_key:
	gnutls_x509_privkey_deinit(key);
	for(i = 0; i < certs_nr; i++)
	{
		gnutls_x509_crt_deinit(certs[i]);
	}
deinit_pkcs12:
	gnutls_pkcs12_deinit(p12);
free_blob:
	free(p12blob.data);
error:
	return is_success;
}
Пример #7
0
static void privkey_info_int(FILE *outfile, common_info_st * cinfo,
			     gnutls_x509_privkey_t key)
{
	int ret, key_type;
	unsigned int bits = 0;
	size_t size;
	const char *cprint;

	/* Public key algorithm
	 */
	fprintf(outfile, "Public Key Info:\n");
	ret = gnutls_x509_privkey_get_pk_algorithm2(key, &bits);
	fprintf(outfile, "\tPublic Key Algorithm: ");

	key_type = ret;

	cprint = gnutls_pk_algorithm_get_name(key_type);
	fprintf(outfile, "%s\n", cprint ? cprint : "Unknown");
	fprintf(outfile, "\tKey Security Level: %s (%u bits)\n\n",
		gnutls_sec_param_get_name(gnutls_x509_privkey_sec_param
					  (key)), bits);

	/* Print the raw public and private keys
	 */
	if (key_type == GNUTLS_PK_RSA) {
		gnutls_datum_t m, e, d, p, q, u, exp1, exp2;

		ret =
		    gnutls_x509_privkey_export_rsa_raw2(key, &m, &e, &d,
							&p, &q, &u, &exp1,
							&exp2);
		if (ret < 0)
			fprintf(stderr,
				"Error in key RSA data export: %s\n",
				gnutls_strerror(ret));
		else {
			print_rsa_pkey(outfile, &m, &e, &d, &p, &q, &u,
				       &exp1, &exp2, cinfo->cprint);

			gnutls_free(m.data);
			gnutls_free(e.data);
			gnutls_free(d.data);
			gnutls_free(p.data);
			gnutls_free(q.data);
			gnutls_free(u.data);
			gnutls_free(exp1.data);
			gnutls_free(exp2.data);
		}
	} else if (key_type == GNUTLS_PK_DSA) {
		gnutls_datum_t p, q, g, y, x;

		ret =
		    gnutls_x509_privkey_export_dsa_raw(key, &p, &q, &g, &y,
						       &x);
		if (ret < 0)
			fprintf(stderr,
				"Error in key DSA data export: %s\n",
				gnutls_strerror(ret));
		else {
			print_dsa_pkey(outfile, &x, &y, &p, &q, &g,
				       cinfo->cprint);

			gnutls_free(x.data);
			gnutls_free(y.data);
			gnutls_free(p.data);
			gnutls_free(q.data);
			gnutls_free(g.data);
		}
	} else if (key_type == GNUTLS_PK_EC) {
		gnutls_datum_t y, x, k;
		gnutls_ecc_curve_t curve;

		ret =
		    gnutls_x509_privkey_export_ecc_raw(key, &curve, &x, &y,
						       &k);
		if (ret < 0)
			fprintf(stderr,
				"Error in key ECC data export: %s\n",
				gnutls_strerror(ret));
		else {
			cprint = gnutls_ecc_curve_get_name(curve);
			bits = 0;

			print_ecc_pkey(outfile, curve, &k, &x, &y,
				       cinfo->cprint);

			gnutls_free(x.data);
			gnutls_free(y.data);
			gnutls_free(k.data);
		}
	}

	fprintf(outfile, "\n");

	size = lbuffer_size;
	ret = gnutls_x509_privkey_get_seed(key, NULL, lbuffer, &size);
	if (ret >= 0) {
		fprintf(outfile, "Seed: %s\n",
			raw_to_string(lbuffer, size));
	}

	size = lbuffer_size;
	ret =
	     gnutls_x509_privkey_get_key_id(key, GNUTLS_KEYID_USE_SHA256, lbuffer, &size);
	if (ret < 0) {
		fprintf(stderr, "Error in key id calculation: %s\n",
			gnutls_strerror(ret));
	} else {
		gnutls_datum_t art;

		fprintf(outfile, "Public Key ID:\n\tsha256:%s\n",
			raw_to_string(lbuffer, size));

		size = lbuffer_size;
		ret =
		     gnutls_x509_privkey_get_key_id(key, GNUTLS_KEYID_USE_SHA1, lbuffer, &size);
		if (ret >= 0) {
			fprintf(outfile, "\tsha1:%s\n",
				raw_to_string(lbuffer, size));
		}

		ret =
		    gnutls_random_art(GNUTLS_RANDOM_ART_OPENSSH, cprint,
				      bits, lbuffer, size, &art);
		if (ret >= 0) {
			fprintf(outfile, "Public key's random art:\n%s\n",
				art.data);
			gnutls_free(art.data);
		}

	}
	fprintf(outfile, "\n");

}