/* * GnuTLS PKCS#11 support * Copyright (C) 2010 Free Software Foundation * * Author: Nikos Mavrogiannopoulos * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct gnutls_privkey_st { gnutls_privkey_type_t type; gnutls_pk_algorithm_t pk_algorithm; union { gnutls_x509_privkey_t x509; gnutls_pkcs11_privkey_t pkcs11; #ifdef ENABLE_OPENPGP gnutls_openpgp_privkey_t openpgp; #endif } key; unsigned int flags; }; /** * gnutls_privkey_get_type: * @key: should contain a #gnutls_privkey_t structure * * This function will return the type of the private key. This is * actually the type of the subsystem used to set this private key. * * Returns: a member of the #gnutls_privkey_type_t enumeration on * success, or a negative value on error. **/ gnutls_privkey_type_t gnutls_privkey_get_type(gnutls_privkey_t key) { return key->type; } /** * gnutls_privkey_get_pk_algorithm: * @key: should contain a #gnutls_privkey_t structure * @bits: If set will return the number of bits of the parameters (may be NULL) * * This function will return the public key algorithm of a private * key and if possible will return a number of bits that indicates * the security parameter of the key. * * Returns: a member of the #gnutls_pk_algorithm_t enumeration on * success, or a negative value on error. **/ int gnutls_privkey_get_pk_algorithm(gnutls_privkey_t key, unsigned int *bits) { switch (key->type) { #ifdef ENABLE_OPENPGP case GNUTLS_PRIVKEY_OPENPGP: return gnutls_openpgp_privkey_get_pk_algorithm(key->key. openpgp, bits); #endif case GNUTLS_PRIVKEY_PKCS11: return gnutls_pkcs11_privkey_get_pk_algorithm(key->key. pkcs11, bits); case GNUTLS_PRIVKEY_X509: if (bits) *bits = _gnutls_mpi_get_nbits(key->key.x509-> params[0]); return gnutls_x509_privkey_get_pk_algorithm(key->key.x509); default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } } /** * gnutls_privkey_init: * @key: The structure to be initialized * * This function will initialize an private key structure. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_privkey_init(gnutls_privkey_t * key) { *key = gnutls_calloc(1, sizeof(struct gnutls_privkey_st)); if (*key == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } return 0; } /** * gnutls_privkey_deinit: * @key: The structure to be deinitialized * * This function will deinitialize a private key structure. **/ void gnutls_privkey_deinit(gnutls_privkey_t key) { if (key->flags & GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE) switch (key->type) { #ifdef ENABLE_OPENPGP case GNUTLS_PRIVKEY_OPENPGP: return gnutls_openpgp_privkey_deinit(key->key. openpgp); #endif case GNUTLS_PRIVKEY_PKCS11: return gnutls_pkcs11_privkey_deinit(key->key. pkcs11); case GNUTLS_PRIVKEY_X509: return gnutls_x509_privkey_deinit(key->key.x509); } gnutls_free(key); } /** * gnutls_privkey_import_pkcs11: * @pkey: The private key * @key: The private key to be imported * @flags: should be zero * * This function will import the given private key to the abstract * #gnutls_privkey_t structure. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_privkey_import_pkcs11(gnutls_privkey_t pkey, gnutls_pkcs11_privkey_t key, unsigned int flags) { pkey->key.pkcs11 = key; pkey->type = GNUTLS_PRIVKEY_PKCS11; pkey->pk_algorithm = gnutls_pkcs11_privkey_get_pk_algorithm(key, NULL); pkey->flags = flags; return 0; } /** * gnutls_privkey_import_x509: * @pkey: The private key * @key: The private key to be imported * @flags: should be zero * * This function will import the given private key to the abstract * #gnutls_privkey_t structure. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_privkey_import_x509(gnutls_privkey_t pkey, gnutls_x509_privkey_t key, unsigned int flags) { pkey->key.x509 = key; pkey->type = GNUTLS_PRIVKEY_X509; pkey->pk_algorithm = gnutls_x509_privkey_get_pk_algorithm(key); pkey->flags = flags; return 0; } #ifdef ENABLE_OPENPGP /** * gnutls_privkey_import_openpgp: * @pkey: The private key * @key: The private key to be imported * @flags: should be zero * * This function will import the given private key to the abstract * #gnutls_privkey_t structure. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_privkey_import_openpgp(gnutls_privkey_t pkey, gnutls_openpgp_privkey_t key, unsigned int flags) { pkey->key.openpgp = key; pkey->type = GNUTLS_PRIVKEY_OPENPGP; pkey->pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm(key, NULL); pkey->flags = flags; return 0; } #endif /** * gnutls_privkey_sign_data: * @signer: Holds the key * @digest: should be a digest algorithm * @flags: should be 0 for now * @data: holds the data to be signed * @signature: will contain the signature allocate with gnutls_malloc() * * This function will sign the given data using a signature algorithm * supported by the private key. Signature algorithms are always used * together with a hash functions. Different hash functions may be * used for the RSA algorithm, but only SHA-1 for the DSA keys. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_privkey_sign_data(gnutls_privkey_t signer, gnutls_digest_algorithm_t hash, unsigned int flags, const gnutls_datum_t * data, gnutls_datum_t * signature) { int ret; gnutls_datum_t digest; switch (signer->pk_algorithm) { case GNUTLS_PK_RSA: ret = pk_pkcs1_rsa_hash(hash, data, &digest); if (ret < 0) { gnutls_assert(); return ret; } break; case GNUTLS_PK_DSA: ret = pk_dsa_hash(hash, data, &digest); if (ret < 0) { gnutls_assert(); return ret; } break; default: gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } ret = gnutls_privkey_sign_hash(signer, &digest, signature); _gnutls_free_datum(&digest); if (ret < 0) { gnutls_assert(); return ret; } return 0; } /** * gnutls_privkey_sign_hash: * @key: Holds the key * @data: holds the data to be signed * @signature: will contain the signature allocate with gnutls_malloc() * * This function will sign the given data using a signature algorithm * supported by the private key. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_privkey_sign_hash(gnutls_privkey_t key, const gnutls_datum_t * hash, gnutls_datum_t * signature) { switch (key->type) { #ifdef ENABLE_OPENPGP case GNUTLS_PRIVKEY_OPENPGP: return gnutls_openpgp_privkey_sign_hash(key->key.openpgp, hash, signature); #endif case GNUTLS_PRIVKEY_PKCS11: return gnutls_pkcs11_privkey_sign_hash(key->key.pkcs11, hash, signature); case GNUTLS_PRIVKEY_X509: return gnutls_x509_privkey_sign_hash(key->key.x509, hash, signature); default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } } /** * gnutls_privkey_decrypt_data: * @key: Holds the key * @flags: zero for now * @ciphertext: holds the data to be decrypted * @plaintext: will contain the decrypted data, allocated with gnutls_malloc() * * This function will decrypt the given data using the algorithm * supported by the private key. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_privkey_decrypt_data(gnutls_privkey_t key, unsigned int flags, const gnutls_datum_t * ciphertext, gnutls_datum_t * plaintext) { if (key->pk_algorithm != GNUTLS_PK_RSA) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } switch (key->type) { #ifdef ENABLE_OPENPGP case GNUTLS_PRIVKEY_OPENPGP: return gnutls_openpgp_privkey_decrypt_data(key->key. openpgp, flags, ciphertext, plaintext); #endif case GNUTLS_PRIVKEY_X509: return _gnutls_pkcs1_rsa_decrypt(plaintext, ciphertext, key->key.x509->params, key->key.x509-> params_size, 2); case GNUTLS_PRIVKEY_PKCS11: return gnutls_pkcs11_privkey_decrypt_data(key->key.pkcs11, flags, ciphertext, plaintext); default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } }