- Support for PKCS#11 through the use of the pkcs11-helper library

This commit is contained in:
Paul Bakker 2011-01-18 15:27:19 +00:00
parent 0f5f72e949
commit 43b7e35b25
11 changed files with 517 additions and 19 deletions

View File

@ -17,6 +17,8 @@ Note: Most of these features have been donated by Fox-IT
status, objects and configuration
+ Added verification callback on certificate chain
verification to allow external blacklisting
* Added support for PKCS#11 through the use of the
libpkcs11-helper library
Changes
* x509parse_time_expired() checks time in addition to

View File

@ -319,6 +319,16 @@
*/
#define POLARSSL_SSL_TLS_C
/*
* Module: library/ssl_srv.c
* Caller: library/ssl_cli.c
* library/ssl_srv.c
*
* This module is required for SSL/TLS PKCS #11 smartcard support.
* Requires the presence of the PKCS#11 helper library (libpkcs11-helper)
*/
#define POLARSSL_PKCS11_C
/*
* Module: library/timing.c
* Caller: library/havege.c

127
include/polarssl/pkcs11.h Normal file
View File

@ -0,0 +1,127 @@
/**
* \file pkcs11.h
*
* \brief Wrapper for PKCS#11 library libpkcs11-helper
*
* \author Adriaan de Jong <dejong@fox-it.com>
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* 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.
*/
#ifndef PKCS11_H_
#define PKCS11_H_
#include "polarssl/config.h"
#if defined(POLARSSL_PKCS11_C)
#include "polarssl/x509.h"
#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
/**
* Context for PKCS #11 private keys.
*/
typedef struct {
pkcs11h_certificate_t pkcs11h_cert;
int len;
} pkcs11_context;
/**
* Fill in a PolarSSL certificate, based on the given PKCS11 helper certificate.
*
* \param cert X.509 certificate to fill
* \param pkcs11h_cert PKCS #11 helper certificate
*
* \return 0 on success.
*/
int pkcs11_x509_cert_init( x509_cert *cert, pkcs11h_certificate_t pkcs11h_cert );
/**
* Initialise a pkcs11_context, storing the given certificate. Note that the
* pkcs11_context will take over control of the certificate, freeing it when
* done.
*
* \param priv_key Private key structure to fill.
* \param pkcs11_cert PKCS #11 helper certificate
*
* \return 0 on success
*/
int pkcs11_priv_key_init( pkcs11_context *priv_key,
pkcs11h_certificate_t pkcs11_cert );
/**
* Free the contents of the given private key context. Note that the structure
* itself is not freed.
*
* \param priv_key Private key structure to cleanup
*/
void pkcs11_priv_key_free( pkcs11_context *priv_key );
/**
* \brief Do an RSA private key decrypt, then remove the message padding
*
* \param ctx PKCS #11 context
* \param mode must be RSA_PRIVATE, for compatibility with rsa.c's signature
* \param input buffer holding the encrypted data
* \param output buffer that will hold the plaintext
* \param olen will contain the plaintext length
* \param output_max_len maximum length of the output buffer
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The output buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
* an error is thrown.
*/
int pkcs11_decrypt( pkcs11_context *ctx,
int mode, int *olen,
const unsigned char *input,
unsigned char *output,
int output_max_len );
/**
* \brief Do a private RSA to sign a message digest
*
* \param ctx PKCS #11 context
* \param mode must be RSA_PRIVATE, for compatibility with rsa.c's signature
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen message digest length (for SIG_RSA_RAW only)
* \param hash buffer holding the message digest
* \param sig buffer that will hold the ciphertext
*
* \return 0 if the signing operation was successful,
* or an POLARSSL_ERR_RSA_XXX error code
*
* \note The "sig" buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int pkcs11_sign( pkcs11_context *ctx,
int mode,
int hash_id,
int hashlen,
const unsigned char *hash,
unsigned char *sig );
#endif /* POLARSSL_PKCS11_C */
#endif /* PKCS11_H_ */

View File

@ -35,6 +35,11 @@
#include "polarssl/md5.h"
#include "polarssl/sha1.h"
#include "polarssl/x509.h"
#include "polarssl/config.h"
#if defined(POLARSSL_PKCS11_C)
#include "polarssl/pkcs11.h"
#endif
/*
* SSL Error codes
@ -268,6 +273,9 @@ struct _ssl_context
* PKI layer
*/
rsa_context *rsa_key; /*!< own RSA private key */
#if defined(POLARSSL_PKCS11_C)
pkcs11_context *pkcs11_key; /*!< own PKCS#11 RSA private key */
#endif
x509_cert *own_cert; /*!< own X.509 certificate */
x509_cert *ca_chain; /*!< own trusted CA chain */
x509_crl *ca_crl; /*!< trusted CA CRLs */
@ -480,6 +488,18 @@ void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain,
void ssl_set_own_cert( ssl_context *ssl, x509_cert *own_cert,
rsa_context *rsa_key );
#if defined(POLARSSL_PKCS11_C)
/**
* \brief Set own certificate and PKCS#11 private key
*
* \param ssl SSL context
* \param own_cert own public certificate
* \param pkcs11_key own PKCS#11 RSA key
*/
void ssl_set_own_cert_pkcs11( ssl_context *ssl, x509_cert *own_cert,
pkcs11_context *pkcs11_key );
#endif
/**
* \brief Set the Diffie-Hellman public P and G values,
* read as hexadecimal strings (server-side only)

View File

@ -26,7 +26,8 @@ OBJS= aes.o arc4.o base64.o \
ssl_cli.o ssl_srv.o ssl_tls.o \
timing.o x509parse.o xtea.o \
camellia.o version.o md.o \
md_wrap.o cipher.o cipher_wrap.o
md_wrap.o cipher.o cipher_wrap.o \
pkcs11.o
.SILENT:

239
library/pkcs11.c Normal file
View File

@ -0,0 +1,239 @@
/**
* \file pkcs11.c
*
* \brief Wrapper for PKCS#11 library libpkcs11-helper
*
* \author Adriaan de Jong <dejong@fox-it.com>
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* 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 <stdlib.h>
#include <string.h>
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, int *olen,
const unsigned char *input,
unsigned char *output,
int 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,
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) */

View File

@ -30,6 +30,10 @@
#include "polarssl/debug.h"
#include "polarssl/ssl.h"
#if defined(POLARSSL_PKCS11_C)
#include "polarssl/pkcs11.h"
#endif /* defined(POLARSSL_PKCS11_C) */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@ -635,8 +639,15 @@ static int ssl_write_certificate_verify( ssl_context *ssl )
if( ssl->rsa_key == NULL )
{
#if defined(POLARSSL_PKCS11_C)
if( ssl->pkcs11_key == NULL )
{
#endif /* defined(POLARSSL_PKCS11_C) */
SSL_DEBUG_MSG( 1, ( "got no private key" ) );
return( POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED );
#if defined(POLARSSL_PKCS11_C)
}
#endif /* defined(POLARSSL_PKCS11_C) */
}
/*
@ -644,14 +655,30 @@ static int ssl_write_certificate_verify( ssl_context *ssl )
*/
ssl_calc_verify( ssl, hash );
if ( ssl->rsa_key )
n = ssl->rsa_key->len;
#if defined(POLARSSL_PKCS11_C)
else
n = ssl->pkcs11_key->len;
#endif /* defined(POLARSSL_PKCS11_C) */
ssl->out_msg[4] = (unsigned char)( n >> 8 );
ssl->out_msg[5] = (unsigned char)( n );
if( ( ret = rsa_pkcs1_sign( ssl->rsa_key, RSA_PRIVATE, SIG_RSA_RAW,
36, hash, ssl->out_msg + 6 ) ) != 0 )
if( ssl->rsa_key )
{
SSL_DEBUG_RET( 1, "rsa_pkcs1_sign", ret );
ret = rsa_pkcs1_sign( ssl->rsa_key, RSA_PRIVATE, SIG_RSA_RAW,
36, hash, ssl->out_msg + 6 );
} else {
#if defined(POLARSSL_PKCS11_C)
ret = pkcs11_sign( ssl->pkcs11_key, RSA_PRIVATE, SIG_RSA_RAW,
36, hash, ssl->out_msg + 6 );
#endif /* defined(POLARSSL_PKCS11_C) */
}
if (ret != 0)
{
SSL_DEBUG_RET( 1, "pkcs1_sign", ret );
return( ret );
}

View File

@ -30,6 +30,10 @@
#include "polarssl/debug.h"
#include "polarssl/ssl.h"
#if defined(POLARSSL_PKCS11_C)
#include "polarssl/pkcs11.h"
#endif /* defined(POLARSSL_PKCS11_C) */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@ -521,7 +525,7 @@ static int ssl_write_certificate_request( ssl_context *ssl )
static int ssl_write_server_key_exchange( ssl_context *ssl )
{
int ret, n;
int ret, n, rsa_key_len = 0;
unsigned char hash[36];
md5_context md5;
sha1_context sha1;
@ -543,6 +547,20 @@ static int ssl_write_server_key_exchange( ssl_context *ssl )
SSL_DEBUG_MSG( 1, ( "support for dhm is not available" ) );
return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
#else
if( ssl->rsa_key == NULL )
{
#if defined(POLARSSL_PKCS11_C)
if( ssl->pkcs11_key == NULL )
{
#endif /* defined(POLARSSL_PKCS11_C) */
SSL_DEBUG_MSG( 1, ( "got no private key" ) );
return( POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED );
#if defined(POLARSSL_PKCS11_C)
}
#endif /* defined(POLARSSL_PKCS11_C) */
}
/*
* Ephemeral DH parameters:
*
@ -589,21 +607,37 @@ static int ssl_write_server_key_exchange( ssl_context *ssl )
SSL_DEBUG_BUF( 3, "parameters hash", hash, 36 );
ssl->out_msg[4 + n] = (unsigned char)( ssl->rsa_key->len >> 8 );
ssl->out_msg[5 + n] = (unsigned char)( ssl->rsa_key->len );
if ( ssl->rsa_key )
rsa_key_len = ssl->rsa_key->len;
#if defined(POLARSSL_PKCS11_C)
else
rsa_key_len = ssl->pkcs11_key->len;
#endif /* defined(POLARSSL_PKCS11_C) */
ssl->out_msg[4 + n] = (unsigned char)( rsa_key_len >> 8 );
ssl->out_msg[5 + n] = (unsigned char)( rsa_key_len );
if ( ssl->rsa_key )
{
ret = rsa_pkcs1_sign( ssl->rsa_key, RSA_PRIVATE,
SIG_RSA_RAW, 36, hash, ssl->out_msg + 6 + n );
}
#if defined(POLARSSL_PKCS11_C)
else {
ret = pkcs11_sign( ssl->pkcs11_key, RSA_PRIVATE,
SIG_RSA_RAW, 36, hash, ssl->out_msg + 6 + n );
}
#endif /* defined(POLARSSL_PKCS11_C) */
if( ret != 0 )
{
SSL_DEBUG_RET( 1, "rsa_pkcs1_sign", ret );
SSL_DEBUG_RET( 1, "pkcs1_sign", ret );
return( ret );
}
SSL_DEBUG_BUF( 3, "my RSA sig", ssl->out_msg + 6 + n,
ssl->rsa_key->len );
SSL_DEBUG_BUF( 3, "my RSA sig", ssl->out_msg + 6 + n, rsa_key_len );
ssl->out_msglen = 6 + n + ssl->rsa_key->len;
ssl->out_msglen = 6 + n + rsa_key_len;
ssl->out_msgtype = SSL_MSG_HANDSHAKE;
ssl->out_msg[0] = SSL_HS_SERVER_KEY_EXCHANGE;
@ -713,11 +747,29 @@ static int ssl_parse_client_key_exchange( ssl_context *ssl )
}
else
{
if( ssl->rsa_key == NULL )
{
#if defined(POLARSSL_PKCS11_C)
if( ssl->pkcs11_key == NULL )
{
#endif
SSL_DEBUG_MSG( 1, ( "got no private key" ) );
return( POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED );
#if defined(POLARSSL_PKCS11_C)
}
#endif
}
/*
* Decrypt the premaster using own private RSA key
*/
i = 4;
if( ssl->rsa_key )
n = ssl->rsa_key->len;
#if defined(POLARSSL_PKCS11_C)
else
n = ssl->pkcs11_key->len;
#endif
ssl->pmslen = 48;
if( ssl->minor_ver != SSL_MINOR_VERSION_0 )
@ -737,9 +789,18 @@ static int ssl_parse_client_key_exchange( ssl_context *ssl )
return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
}
if( ssl->rsa_key ) {
ret = rsa_pkcs1_decrypt( ssl->rsa_key, RSA_PRIVATE, &ssl->pmslen,
ssl->in_msg + i, ssl->premaster,
sizeof(ssl->premaster) );
}
#if defined(POLARSSL_PKCS11_C)
else {
ret = pkcs11_decrypt( ssl->pkcs11_key, RSA_PRIVATE, &ssl->pmslen,
ssl->in_msg + i, ssl->premaster,
sizeof(ssl->premaster) );
}
#endif /* defined(POLARSSL_PKCS11_C) */
if( ret != 0 || ssl->pmslen != 48 ||
ssl->premaster[0] != ssl->max_major_ver ||

View File

@ -1796,6 +1796,15 @@ void ssl_set_own_cert( ssl_context *ssl, x509_cert *own_cert,
ssl->rsa_key = rsa_key;
}
#if defined(POLARSSL_PKCS11_C)
void ssl_set_own_cert_pkcs11( ssl_context *ssl, x509_cert *own_cert,
pkcs11_context *pkcs11_key )
{
ssl->own_cert = own_cert;
ssl->pkcs11_key = pkcs11_key;
}
#endif
int ssl_set_dh_param( ssl_context *ssl, const char *dhm_P, const char *dhm_G )
{
int ret;

View File

@ -1,6 +1,7 @@
# To compile on SunOS: add "-lsocket -lnsl" to LDFLAGS
# To compile on MinGW: add "-lws2_32" to LDFLAGS
# To compile with PKCS11: add "-lpkcs11-helper" to LDFLAGS
CFLAGS = -I../include -D_FILE_OFFSET_BITS=64 -Wall -Wdeclaration-after-statement
OFLAGS = -O

View File

@ -1,6 +1,7 @@
# To compile on SunOS: add "-lsocket -lnsl" to LDFLAGS
# To compile on MinGW: add "-lws2_32" to LDFLAGS
# To compile with PKCS11: add "-lpkcs11-helper" to LDFLAGS
CFLAGS = -I../include -D_FILE_OFFSET_BITS=64 -Wall -Wdeclaration-after-statement \
-Wno-unused-function -Wno-unused-value