/** * \file pkcs11.c * * \brief Wrapper for PKCS#11 library libpkcs11-helper * * \author Adriaan de Jong * * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved * * This file is part of mbed TLS (https://polarssl.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "polarssl/pkcs11.h" #if defined(POLARSSL_PKCS11_C) #include int pkcs11_x509_cert_init( x509_cert *cert, pkcs11h_certificate_t pkcs11_cert ) { int ret = 1; unsigned char *cert_blob = NULL; size_t cert_blob_size = 0; if( cert == NULL ) { ret = 2; goto cleanup; } if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, NULL, &cert_blob_size ) != CKR_OK ) { ret = 3; goto cleanup; } cert_blob = malloc( cert_blob_size ); if( NULL == cert_blob ) { ret = 4; goto cleanup; } if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, cert_blob, &cert_blob_size ) != CKR_OK ) { ret = 5; goto cleanup; } if( 0 != x509parse_crt(cert, cert_blob, cert_blob_size ) ) { ret = 6; goto cleanup; } ret = 0; cleanup: if( NULL != cert_blob ) free( cert_blob ); return ret; } int pkcs11_priv_key_init( pkcs11_context *priv_key, pkcs11h_certificate_t pkcs11_cert ) { int ret = 1; x509_cert cert; memset( &cert, 0, sizeof( cert ) ); if( priv_key == NULL ) goto cleanup; if( 0 != pkcs11_x509_cert_init( &cert, pkcs11_cert ) ) goto cleanup; priv_key->len = cert.rsa.len; priv_key->pkcs11h_cert = pkcs11_cert; ret = 0; cleanup: x509_free( &cert ); return ret; } void pkcs11_priv_key_free( pkcs11_context *priv_key ) { if( NULL != priv_key ) pkcs11h_certificate_freeCertificate( priv_key->pkcs11h_cert ); } int pkcs11_decrypt( pkcs11_context *ctx, int mode, size_t *olen, const unsigned char *input, unsigned char *output, size_t output_max_len ) { size_t input_len, output_len; if( NULL == ctx ) return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); if( RSA_PUBLIC == mode ) return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); output_len = input_len = ctx->len; if( input_len < 16 || input_len > output_max_len ) return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); /* Determine size of output buffer */ if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, input_len, NULL, &output_len ) != CKR_OK ) { return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); } if( output_len > output_max_len ) return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE ); if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, input_len, output, &output_len ) != CKR_OK ) { return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); } *olen = output_len; return( 0 ); } int pkcs11_sign( pkcs11_context *ctx, int mode, int hash_id, unsigned int hashlen, const unsigned char *hash, unsigned char *sig ) { size_t olen, asn_len; unsigned char *p = sig; if( NULL == ctx ) return POLARSSL_ERR_RSA_BAD_INPUT_DATA; if( RSA_PUBLIC == mode ) return POLARSSL_ERR_RSA_BAD_INPUT_DATA; olen = ctx->len; switch( hash_id ) { case SIG_RSA_RAW: asn_len = 0; memcpy( p, hash, hashlen ); break; case SIG_RSA_MD2: asn_len = OID_SIZE(ASN1_HASH_MDX); memcpy( p, ASN1_HASH_MDX, asn_len ); memcpy( p + asn_len, hash, hashlen ); p[13] = 2; break; case SIG_RSA_MD4: asn_len = OID_SIZE(ASN1_HASH_MDX); memcpy( p, ASN1_HASH_MDX, asn_len ); memcpy( p + asn_len, hash, hashlen ); p[13] = 4; break; case SIG_RSA_MD5: asn_len = OID_SIZE(ASN1_HASH_MDX); memcpy( p, ASN1_HASH_MDX, asn_len ); memcpy( p + asn_len, hash, hashlen ); p[13] = 5; break; case SIG_RSA_SHA1: asn_len = OID_SIZE(ASN1_HASH_SHA1); memcpy( p, ASN1_HASH_SHA1, asn_len ); memcpy( p + 15, hash, hashlen ); break; case SIG_RSA_SHA224: asn_len = OID_SIZE(ASN1_HASH_SHA2X); memcpy( p, ASN1_HASH_SHA2X, asn_len ); memcpy( p + asn_len, hash, hashlen ); p[1] += hashlen; p[14] = 4; p[18] += hashlen; break; case SIG_RSA_SHA256: asn_len = OID_SIZE(ASN1_HASH_SHA2X); memcpy( p, ASN1_HASH_SHA2X, asn_len ); memcpy( p + asn_len, hash, hashlen ); p[1] += hashlen; p[14] = 1; p[18] += hashlen; break; case SIG_RSA_SHA384: asn_len = OID_SIZE(ASN1_HASH_SHA2X); memcpy( p, ASN1_HASH_SHA2X, asn_len ); memcpy( p + asn_len, hash, hashlen ); p[1] += hashlen; p[14] = 2; p[18] += hashlen; break; case SIG_RSA_SHA512: asn_len = OID_SIZE(ASN1_HASH_SHA2X); memcpy( p, ASN1_HASH_SHA2X, asn_len ); memcpy( p + asn_len, hash, hashlen ); p[1] += hashlen; p[14] = 3; p[18] += hashlen; break; default: return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); } if( pkcs11h_certificate_signAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, sig, asn_len + hashlen, sig, &olen ) != CKR_OK ) { return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); } return( 0 ); } #endif /* defined(POLARSSL_PKCS11_C) */