mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-11-22 18:35:42 +01:00
b23b04d177
Change the buffer zeroization so that it happens earlier
570 lines
20 KiB
C
570 lines
20 KiB
C
/*
|
|
* Generic wrapper for Cryptoki (PKCS#11) support
|
|
*
|
|
* Copyright (C) 2017, ARM Limited, All Rights Reserved
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
* not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* This file is part of mbed TLS (https://tls.mbed.org)
|
|
*/
|
|
|
|
#if !defined(MBEDTLS_CONFIG_FILE)
|
|
#include "mbedtls/config.h"
|
|
#else
|
|
#include MBEDTLS_CONFIG_FILE
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_PKCS11_CLIENT_C)
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <pkcs11.h>
|
|
|
|
#include "mbedtls/pkcs11_client.h"
|
|
|
|
#if defined(MBEDTLS_PLATFORM_C)
|
|
#include "mbedtls/platform.h"
|
|
#else
|
|
#include <stdlib.h>
|
|
#define mbedtls_calloc calloc
|
|
#define mbedtls_free free
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(MBEDTLS_PK_C)
|
|
#include "mbedtls/pk.h"
|
|
#include "mbedtls/pk_info.h"
|
|
|
|
#if defined(MBEDTLS_RSA_C)
|
|
#include "mbedtls/bignum.h"
|
|
#include "mbedtls/rsa.h"
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_ECDSA_C)
|
|
#include "mbedtls/asn1.h"
|
|
#include "mbedtls/asn1write.h"
|
|
#include "mbedtls/bignum.h"
|
|
#include "mbedtls/ecdsa.h"
|
|
#include "mbedtls/ecp.h"
|
|
#include "mbedtls/oid.h"
|
|
#endif
|
|
|
|
#define ARRAY_LENGTH( a ) ( sizeof( a ) / sizeof( *( a ) ) )
|
|
|
|
typedef struct {
|
|
mbedtls_pk_type_t key_type; /**< key type */
|
|
CK_SESSION_HANDLE hSession; /**< session handle */
|
|
CK_OBJECT_HANDLE hPublicKey; /**< public key handle (must not be null) */
|
|
CK_OBJECT_HANDLE hPrivateKey; /**< private key handle (may be null) */
|
|
uint16_t bit_length; /**< key length in bits */
|
|
} mbedtls_pk_pkcs11_context_t;
|
|
|
|
static int pkcs11_err_to_mbedtls_pk_err( CK_RV rv )
|
|
{
|
|
switch( rv )
|
|
{
|
|
case CKR_OK:
|
|
return( 0 );
|
|
case CKR_HOST_MEMORY:
|
|
return( MBEDTLS_ERR_PK_ALLOC_FAILED );
|
|
case CKR_ARGUMENTS_BAD:
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
case CKR_KEY_FUNCTION_NOT_PERMITTED:
|
|
return( MBEDTLS_ERR_PK_NOT_PERMITTED );
|
|
case CKR_MECHANISM_INVALID:
|
|
return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
|
|
case CKR_MECHANISM_PARAM_INVALID:
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
case CKR_OBJECT_HANDLE_INVALID:
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
case CKR_SIGNATURE_INVALID:
|
|
return( MBEDTLS_ERR_PK_INVALID_SIGNATURE );
|
|
case CKR_SIGNATURE_LEN_RANGE:
|
|
return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH );
|
|
case CKR_TEMPLATE_INCOMPLETE:
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
case CKR_BUFFER_TOO_SMALL:
|
|
return( MBEDTLS_ERR_PK_BUFFER_TOO_SMALL );
|
|
default:
|
|
return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
|
|
}
|
|
}
|
|
|
|
static size_t pkcs11_pk_get_bitlen( const void *ctx_arg )
|
|
{
|
|
const mbedtls_pk_pkcs11_context_t *ctx = ctx_arg;
|
|
return( ctx->bit_length );
|
|
}
|
|
|
|
static int pkcs11_pk_can_do( const void *ctx_arg, mbedtls_pk_type_t type )
|
|
{
|
|
const mbedtls_pk_pkcs11_context_t *ctx = ctx_arg;
|
|
return( ctx->key_type == mbedtls_pk_representation_type( type ) );
|
|
}
|
|
|
|
static void *pkcs11_pk_alloc( )
|
|
{
|
|
return( mbedtls_calloc( 1, sizeof( mbedtls_pk_pkcs11_context_t ) ) );
|
|
}
|
|
|
|
static void pkcs11_pk_free( void *ctx )
|
|
{
|
|
mbedtls_free( ctx );
|
|
}
|
|
|
|
static size_t pkcs11_pk_signature_size( const void *ctx_arg )
|
|
{
|
|
const mbedtls_pk_pkcs11_context_t *ctx = ctx_arg;
|
|
switch( ctx->key_type )
|
|
{
|
|
case MBEDTLS_PK_RSA:
|
|
return( ( ctx->bit_length + 7 ) / 8 );
|
|
case MBEDTLS_PK_ECKEY:
|
|
return( MBEDTLS_ECDSA_MAX_SIG_LEN( ctx->bit_length ) );
|
|
default:
|
|
return( 0 );
|
|
}
|
|
}
|
|
|
|
#if defined(MBEDTLS_RSA_C)
|
|
static int pkcs11_sign_core( mbedtls_pk_pkcs11_context_t *ctx,
|
|
CK_MECHANISM_TYPE mechanism_type,
|
|
const unsigned char *payload, size_t payload_len,
|
|
unsigned char *sig, size_t *sig_len,
|
|
size_t sig_size )
|
|
{
|
|
CK_ULONG ck_sig_len = sig_size;
|
|
CK_MECHANISM mechanism = { mechanism_type, NULL_PTR, 0 };
|
|
CK_RV rv;
|
|
rv = C_SignInit( ctx->hSession, &mechanism, ctx->hPrivateKey );
|
|
if( rv != CKR_OK )
|
|
goto exit;
|
|
rv = C_Sign( ctx->hSession, (CK_BYTE_PTR) payload, payload_len,
|
|
sig, &ck_sig_len );
|
|
if( rv != CKR_OK )
|
|
goto exit;
|
|
*sig_len = ck_sig_len;
|
|
exit:
|
|
if( rv != CKR_OK )
|
|
memset( sig, 0, ck_sig_len );
|
|
return( pkcs11_err_to_mbedtls_pk_err( rv ) );
|
|
}
|
|
#endif /* MBEDTLS_RSA_C */
|
|
|
|
#if defined(MBEDTLS_RSA_C)
|
|
static int pkcs11_sign_rsa( mbedtls_pk_pkcs11_context_t *ctx,
|
|
const unsigned char *digest_info,
|
|
size_t digest_info_len,
|
|
unsigned char *sig, size_t *sig_len )
|
|
{
|
|
return( pkcs11_sign_core( ctx, CKM_RSA_PKCS,
|
|
digest_info, digest_info_len,
|
|
sig, sig_len, ( ctx->bit_length + 7 ) / 8 ) );
|
|
}
|
|
#endif /* MBEDTLS_RSA_C */
|
|
|
|
static int pkcs11_sign( void *ctx_arg,
|
|
mbedtls_md_type_t md_alg,
|
|
const unsigned char *hash, size_t hash_len,
|
|
unsigned char *sig, size_t *sig_len,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng )
|
|
{
|
|
mbedtls_pk_pkcs11_context_t *ctx = ctx_arg;
|
|
int ret;
|
|
|
|
*sig_len = 0;
|
|
|
|
/* This function takes size_t arguments but the underlying layer
|
|
takes unsigned long. Either type may be smaller than the other.
|
|
Legitimate values won't overflow either type but we still need
|
|
to check for overflow for robustness. */
|
|
if( hash_len > (CK_ULONG)( -1 ) )
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
(void) f_rng;
|
|
(void) p_rng;
|
|
|
|
switch( ctx->key_type )
|
|
{
|
|
#if defined(MBEDTLS_RSA_C)
|
|
case MBEDTLS_PK_RSA:
|
|
/* There is no mechanism in PKCS#11 that computes a PKCS#1 v1.5
|
|
* signature from a hash value and a hash type, only mechanisms
|
|
* that include the hash calculation and a mechanism that expects
|
|
* a DigestInfo (encoded hash that isn't padded). So we use the
|
|
* mechanism that expects a DigestInfo, and calculate the DigestInfo
|
|
* ourselves if needed. */
|
|
if( md_alg == MBEDTLS_MD_NONE )
|
|
{
|
|
ret = pkcs11_sign_rsa( ctx, hash, hash_len, sig, sig_len );
|
|
}
|
|
else
|
|
{
|
|
unsigned char digest_info[MBEDTLS_RSA_PKCS1_DIGESTINFO_MAX_SIZE];
|
|
unsigned char *p = digest_info + sizeof( digest_info );
|
|
size_t digest_info_len;
|
|
if( mbedtls_rsa_emsa_pkcs1_v15_encode_digestinfo(
|
|
&p, digest_info,
|
|
md_alg, hash, hash_len ) != 0 )
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
digest_info_len = digest_info + sizeof( digest_info ) - p;
|
|
ret = pkcs11_sign_rsa( ctx, p, digest_info_len, sig, sig_len );
|
|
}
|
|
break;
|
|
#endif /* MBEDTLS_RSA_C */
|
|
default:
|
|
return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
|
|
}
|
|
|
|
return( ret );
|
|
}
|
|
|
|
static int pkcs11_verify_core( mbedtls_pk_pkcs11_context_t *ctx,
|
|
CK_MECHANISM_TYPE mechanism_type,
|
|
const unsigned char *payload, size_t payload_len,
|
|
const unsigned char *sig, size_t sig_len )
|
|
{
|
|
CK_MECHANISM mechanism = { mechanism_type, NULL_PTR, 0 };
|
|
CK_RV rv;
|
|
|
|
rv = C_VerifyInit( ctx->hSession, &mechanism, ctx->hPublicKey );
|
|
if( rv != CKR_OK )
|
|
goto exit;
|
|
rv = C_Verify( ctx->hSession, (CK_BYTE_PTR) payload, payload_len,
|
|
(CK_BYTE_PTR) sig, sig_len );
|
|
if( rv != CKR_OK )
|
|
goto exit;
|
|
|
|
exit:
|
|
return( pkcs11_err_to_mbedtls_pk_err( rv ) );
|
|
}
|
|
|
|
static int pkcs11_verify( void *ctx_arg,
|
|
mbedtls_md_type_t md_alg,
|
|
const unsigned char *hash, size_t hash_len,
|
|
const unsigned char *sig, size_t sig_len)
|
|
{
|
|
mbedtls_pk_pkcs11_context_t *ctx = ctx_arg;
|
|
|
|
/* This function takes size_t arguments but the underlying layer
|
|
takes unsigned long. Either type may be smaller than the other.
|
|
Legitimate values won't overflow either type but we still need
|
|
to check for overflow for robustness. */
|
|
if( hash_len > (CK_ULONG)( -1 ) )
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
|
|
switch( ctx->key_type )
|
|
{
|
|
#if defined(MBEDTLS_RSA_C)
|
|
case MBEDTLS_PK_RSA:
|
|
/* There is no mechanism in PKCS#11 that computes a PKCS#1 v1.5
|
|
* signature from a hash value and a hash type, only mechanisms
|
|
* that include the hash calculation and a mechanism that expects
|
|
* a DigestInfo (encoded hash that isn't padded). So we use the
|
|
* mechanism that expects a DigestInfo, and calculate the DigestInfo
|
|
* ourselves if needed. */
|
|
if( md_alg == MBEDTLS_MD_NONE )
|
|
{
|
|
return( pkcs11_verify_core( ctx, CKM_RSA_PKCS,
|
|
hash, hash_len,
|
|
sig, sig_len ) );
|
|
}
|
|
else
|
|
{
|
|
unsigned char digest_info[MBEDTLS_RSA_PKCS1_DIGESTINFO_MAX_SIZE];
|
|
unsigned char *p = digest_info + sizeof( digest_info );
|
|
size_t digest_info_len;
|
|
if( mbedtls_rsa_emsa_pkcs1_v15_encode_digestinfo(
|
|
&p, digest_info,
|
|
md_alg, hash, hash_len ) != 0 )
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
digest_info_len = digest_info + sizeof( digest_info ) - p;
|
|
return( pkcs11_verify_core( ctx, CKM_RSA_PKCS,
|
|
p, digest_info_len,
|
|
sig, sig_len ) );
|
|
}
|
|
break;
|
|
#endif /* MBEDTLS_RSA_C */
|
|
default:
|
|
return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
|
|
}
|
|
}
|
|
|
|
static const mbedtls_pk_info_t mbedtls_pk_pkcs11_info =
|
|
MBEDTLS_PK_OPAQUE_INFO_1( "pkcs11"
|
|
, pkcs11_pk_get_bitlen
|
|
, pkcs11_pk_can_do //can_do
|
|
, pkcs11_pk_signature_size
|
|
, pkcs11_verify
|
|
, pkcs11_sign
|
|
, NULL //pkcs11_decrypt
|
|
, NULL //pkcs11_encrypt
|
|
, NULL //check_pair_func
|
|
, pkcs11_pk_alloc
|
|
, pkcs11_pk_free
|
|
, NULL //debug_func
|
|
);
|
|
|
|
int mbedtls_pk_setup_pkcs11( mbedtls_pk_context *ctx,
|
|
CK_SESSION_HANDLE hSession,
|
|
CK_OBJECT_HANDLE hPublicKey,
|
|
CK_OBJECT_HANDLE hPrivateKey )
|
|
{
|
|
CK_OBJECT_CLASS public_key_class = -1, private_key_class = -1;
|
|
CK_KEY_TYPE public_key_type = -1, private_key_type = -1;
|
|
mbedtls_pk_type_t can_do;
|
|
CK_ATTRIBUTE attributes[] = {
|
|
{CKA_CLASS, &public_key_class, sizeof( public_key_class )},
|
|
{CKA_KEY_TYPE, &public_key_type, sizeof( public_key_type )},
|
|
};
|
|
CK_RV rv;
|
|
uint16_t key_size = 0;
|
|
|
|
rv = C_GetAttributeValue( hSession, hPublicKey,
|
|
attributes, ARRAY_LENGTH( attributes ) );
|
|
if( rv != CKR_OK )
|
|
return( pkcs11_err_to_mbedtls_pk_err( rv ) );
|
|
if( public_key_class != CKO_PUBLIC_KEY )
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
|
|
if( hPrivateKey != CK_INVALID_HANDLE )
|
|
{
|
|
attributes[0].pValue = &private_key_class;
|
|
attributes[1].pValue = &private_key_type;
|
|
rv = C_GetAttributeValue( hSession, hPrivateKey,
|
|
attributes, ARRAY_LENGTH( attributes ) );
|
|
if( rv != CKR_OK )
|
|
return( pkcs11_err_to_mbedtls_pk_err( rv ) );
|
|
if( private_key_class != CKO_PRIVATE_KEY )
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
if( public_key_type != private_key_type )
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
}
|
|
|
|
switch( public_key_type ) {
|
|
#if defined(MBEDTLS_RSA_C)
|
|
case CKK_RSA:
|
|
can_do = MBEDTLS_PK_RSA;
|
|
{
|
|
CK_ULONG modulus_bits;
|
|
attributes[0].type = CKA_MODULUS_BITS;
|
|
attributes[0].pValue = &modulus_bits;
|
|
attributes[0].ulValueLen = sizeof( modulus_bits );
|
|
rv = C_GetAttributeValue( hSession, hPublicKey, attributes, 1 );
|
|
if( rv != CKR_OK )
|
|
return( pkcs11_err_to_mbedtls_pk_err( rv ) );
|
|
if( modulus_bits > (uint16_t)( -1 ) )
|
|
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
|
key_size = modulus_bits;
|
|
}
|
|
break;
|
|
#endif /* MBEDTLS_RSA_C */
|
|
default:
|
|
can_do = MBEDTLS_PK_OPAQUE;
|
|
break;
|
|
}
|
|
|
|
{
|
|
int ret = mbedtls_pk_setup( ctx, &mbedtls_pk_pkcs11_info );
|
|
if( ret != 0 )
|
|
return( MBEDTLS_ERR_PK_ALLOC_FAILED );
|
|
}
|
|
{
|
|
mbedtls_pk_pkcs11_context_t *pkcs11_ctx = ctx->pk_ctx;
|
|
pkcs11_ctx->key_type = can_do;
|
|
pkcs11_ctx->bit_length = key_size;
|
|
pkcs11_ctx->hSession = hSession;
|
|
pkcs11_ctx->hPublicKey = hPublicKey;
|
|
pkcs11_ctx->hPrivateKey = hPrivateKey;
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C)
|
|
static int mpi_to_ck( const mbedtls_mpi *mpi,
|
|
CK_ATTRIBUTE *attr, CK_ATTRIBUTE_TYPE at,
|
|
unsigned char **p, size_t len )
|
|
{
|
|
if( mbedtls_mpi_write_binary( mpi, *p, len ) != 0 )
|
|
return( 0 );
|
|
attr->type = at;
|
|
attr->pValue = *p;
|
|
attr->ulValueLen = len;
|
|
*p += len;
|
|
return( 1 );
|
|
}
|
|
#define MPI_TO_CK( mpi, attr, at, p, len ) \
|
|
do \
|
|
{ \
|
|
if( !mpi_to_ck( ( mpi ), ( attr ), ( at ), ( p ), ( len ) ) ) \
|
|
{ \
|
|
rv = CKR_ARGUMENTS_BAD; \
|
|
goto exit; \
|
|
} \
|
|
} \
|
|
while( 0 )
|
|
#endif /* defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C) */
|
|
|
|
#define CK_BOOL( x ) ( ( x ) ? CK_TRUE : CK_FALSE )
|
|
|
|
int mbedtls_pk_import_to_pkcs11( const mbedtls_pk_context *ctx,
|
|
uint32_t flags,
|
|
CK_SESSION_HANDLE hSession,
|
|
CK_OBJECT_HANDLE *hPublicKey,
|
|
CK_OBJECT_HANDLE *hPrivateKey )
|
|
{
|
|
CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY;
|
|
CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY;
|
|
CK_KEY_TYPE ck_key_type;
|
|
CK_BBOOL ck_sensitive = CK_BOOL( flags & MBEDTLS_PK_FLAG_SENSITIVE );
|
|
CK_BBOOL ck_extractable = CK_BOOL( flags & MBEDTLS_PK_FLAG_EXTRACTABLE );
|
|
CK_BBOOL ck_sign = CK_BOOL( flags & MBEDTLS_PK_FLAG_SIGN );
|
|
CK_BBOOL ck_verify = CK_BOOL( flags & MBEDTLS_PK_FLAG_VERIFY );
|
|
CK_BBOOL ck_decrypt = CK_BOOL( flags & MBEDTLS_PK_FLAG_DECRYPT );
|
|
CK_BBOOL ck_encrypt = CK_BOOL( flags & MBEDTLS_PK_FLAG_ENCRYPT );
|
|
CK_BBOOL ck_token = CK_BOOL( flags & MBEDTLS_PKCS11_FLAG_TOKEN );
|
|
CK_ATTRIBUTE public_attributes[] = {
|
|
{CKA_CLASS, &cko_public_key, sizeof( cko_public_key )},
|
|
{CKA_KEY_TYPE, &ck_key_type, sizeof( ck_key_type )},
|
|
{CKA_TOKEN, &ck_token, sizeof( ck_token )},
|
|
{CKA_ENCRYPT, &ck_encrypt, sizeof( ck_encrypt )},
|
|
{CKA_VERIFY, &ck_verify, sizeof( ck_verify )},
|
|
#define COMMON_PUBLIC_ATTRIBUTES 5 // number of attributes above
|
|
{-1, NULL, 0},
|
|
{-1, NULL, 0},
|
|
};
|
|
CK_ATTRIBUTE private_attributes[] = {
|
|
{CKA_CLASS, &cko_private_key, sizeof( cko_private_key )},
|
|
{CKA_KEY_TYPE, &ck_key_type, sizeof( ck_key_type )},
|
|
{CKA_TOKEN, &ck_token, sizeof( ck_token )},
|
|
{CKA_DECRYPT, &ck_decrypt, sizeof( ck_decrypt )},
|
|
{CKA_SIGN, &ck_sign, sizeof( ck_sign )},
|
|
{CKA_SENSITIVE, &ck_sensitive, sizeof( ck_sensitive )},
|
|
{CKA_EXTRACTABLE, &ck_extractable, sizeof( ck_extractable )},
|
|
#define COMMON_PRIVATE_ATTRIBUTES 7 // number of attributes above
|
|
{-1, NULL, 0},
|
|
{-1, NULL, 0},
|
|
{-1, NULL, 0},
|
|
{-1, NULL, 0},
|
|
{-1, NULL, 0},
|
|
{-1, NULL, 0},
|
|
{-1, NULL, 0},
|
|
{-1, NULL, 0},
|
|
};
|
|
CK_ATTRIBUTE *public_end = public_attributes + COMMON_PUBLIC_ATTRIBUTES;
|
|
CK_ATTRIBUTE *private_end = private_attributes + COMMON_PRIVATE_ATTRIBUTES;
|
|
#undef COMMON_PUBLIC_ATTRIBUTES
|
|
#undef COMMON_PRIVATE_ATTRIBUTES
|
|
unsigned char *data = NULL;
|
|
CK_RV rv;
|
|
|
|
if( hPublicKey != NULL )
|
|
*hPublicKey = CK_INVALID_HANDLE;
|
|
if( hPrivateKey != NULL )
|
|
*hPrivateKey = CK_INVALID_HANDLE;
|
|
|
|
/* Prepare the data-dependent key attributes */
|
|
switch( mbedtls_pk_representation_type( mbedtls_pk_get_type( ctx ) ) )
|
|
{
|
|
#if defined(MBEDTLS_RSA_C)
|
|
case MBEDTLS_PK_RSA:
|
|
{
|
|
const mbedtls_rsa_context *rsa = mbedtls_pk_rsa( *ctx );
|
|
unsigned char *p;
|
|
size_t half_len = ( rsa->len + 1 ) / 2;
|
|
data = mbedtls_calloc( 1, 3 * rsa->len + 5 * half_len );
|
|
if( data == NULL )
|
|
{
|
|
rv = CKR_HOST_MEMORY;
|
|
goto exit;
|
|
}
|
|
p = data;
|
|
ck_key_type = CKK_RSA;
|
|
MPI_TO_CK( &rsa->N, public_end, CKA_MODULUS, &p, rsa->len );
|
|
*private_end++ = *public_end++;
|
|
MPI_TO_CK( &rsa->E, public_end, CKA_PUBLIC_EXPONENT, &p, rsa->len );
|
|
*private_end++ = *public_end++;
|
|
if( hPrivateKey != NULL )
|
|
{
|
|
MPI_TO_CK( &rsa->D, private_end++,
|
|
CKA_PRIVATE_EXPONENT, &p, rsa->len );
|
|
MPI_TO_CK( &rsa->P, private_end++,
|
|
CKA_PRIME_1, &p, half_len );
|
|
MPI_TO_CK( &rsa->Q, private_end++,
|
|
CKA_PRIME_2, &p, half_len );
|
|
MPI_TO_CK( &rsa->DP, private_end++,
|
|
CKA_EXPONENT_1, &p, half_len );
|
|
MPI_TO_CK( &rsa->DQ, private_end++,
|
|
CKA_EXPONENT_2, &p, half_len );
|
|
MPI_TO_CK( &rsa->QP, private_end++,
|
|
CKA_COEFFICIENT, &p, half_len );
|
|
}
|
|
}
|
|
break;
|
|
#endif /* MBEDTLS_RSA_C */
|
|
default:
|
|
return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
|
|
}
|
|
|
|
if( hPublicKey != NULL )
|
|
{
|
|
*hPublicKey = CK_INVALID_HANDLE;
|
|
rv = C_CreateObject( hSession,
|
|
public_attributes,
|
|
public_end - public_attributes,
|
|
hPublicKey );
|
|
if( rv != CKR_OK )
|
|
goto exit;
|
|
}
|
|
|
|
if( hPrivateKey != NULL )
|
|
{
|
|
rv = C_CreateObject( hSession,
|
|
private_attributes,
|
|
private_end - private_attributes,
|
|
hPrivateKey );
|
|
if( rv != CKR_OK )
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
if( rv != CKR_OK )
|
|
{
|
|
/* In case an error happened, destroy any object that we
|
|
created. In case C_DestroyObject failed, we report the original
|
|
error, but *hPublicKey may contain a valid handle if
|
|
creating the private key failed and then destroying the public key
|
|
also failed (e.g. because the token disconnected). */
|
|
if( hPublicKey != NULL && *hPublicKey != CK_INVALID_HANDLE )
|
|
{
|
|
if( C_DestroyObject( hSession, *hPublicKey ) == CKR_OK )
|
|
*hPublicKey = CK_INVALID_HANDLE;
|
|
}
|
|
if( hPrivateKey != NULL && *hPrivateKey != CK_INVALID_HANDLE )
|
|
{
|
|
if( C_DestroyObject( hSession, *hPrivateKey ) == CKR_OK )
|
|
*hPrivateKey = CK_INVALID_HANDLE;
|
|
}
|
|
}
|
|
mbedtls_free( data );
|
|
return( pkcs11_err_to_mbedtls_pk_err( rv ) );
|
|
}
|
|
|
|
#endif /* MBEDTLS_PK_C */
|
|
|
|
|
|
|
|
#endif /* MBEDTLS_PKCS11_CLIENT_C */
|