我想使用USB令牌(加密狗)中的用户密钥和证书对文件进行签名。
我已经在stackoverflow和其他网站上搜索了一段时间,但除了中的一些好功能之外,没有得到任何有用的东西。NET framework(我没有使用)。
似乎由于密钥没有暴露,加密是由硬件本身完成的。这是否意味着每个硬件制造商都提供自己的API,并且没有通用方法来解决这个问题?
此外,我还了解到,一旦令牌插入计算机,其证书就会加载到系统存储中。是否可以使用存储区中的证书?如何在存储中识别和访问此类证书?那私钥呢?
当证书可以从中提取时,我使用OpenSSL进行数字签名。p12或。pfx文件。
如果我在某个地方错了,请纠正我,我对这个话题是新手。
存在2个选项:
我认为OpenSSL不能用于您的任务-您需要使用CryptoAPI或PKCS#11。
我们的SecureBackbox产品提供了一个统一的高级接口,用于根据各种加密标准并使用PKCS#11和/或CryptoAPI对数据进行签名。对于PKCS#11,您(或进行签名的系统的操作员)仍然需要知道PKCS#11驱动程序DLL的路径。可以从C使用其库版本使用SecureBackbox。
您可以通过使用OpenSSL的引擎并为其提供PKCS#11引擎来实现这一点。
这可以通过命令行(引擎标志)或通过设置引擎来完成。应用程序。openssl发行版的c/in/apps/有很好的例子。
命令行的典型调用形式如下
usr/bin/openssl << EOM
engine dynamic -pre SO_PATH:/Library/OpenSC/lib/engines/engine_pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:opensc-pkcs11.so
req -engine pkcs11 -batch -subj "/CN=moi" -new -key slot_$SLOT-id_$KID -keyform engine -x509 -out cert.pem -text
EOM
这创造了
签名:
${OPENSSL} << EOM || exit 1
engine -vvvv dynamic \
-pre SO_PATH:/Library/OpenSC/lib/engines/engine_pkcs11.so \
-pre ID:pkcs11 \
-pre LIST_ADD:1 \
-pre LOAD \
-pre MODULE_PATH:$PKCS \
-pre PIN:$PIN \
-pre VERBOSE
x509 -engine pkcs11 -req -in req.csr -out signed.pem \
-CAfile $CA \
-keyform engine -key $SLOT:$CAKID \
-cert $CAKID.pem
请注意,对于后者,未修补的openssl不允许引用卡上的证书(仅允许密钥)。因此,首先需要将其提取并存储为文件。
并使用卡上的密钥将客户端身份验证连接到服务器:
${OPENSSL} << EOM || exit 1
engine -vvvv dynamic \
-pre SO_PATH:/Library/OpenSC/lib/engines/engine_pkcs11.so \
-pre ID:pkcs11 \
-pre LIST_ADD:1 \
-pre LOAD \
-pre MODULE_PATH:$PKCS \
-pre PIN:$PIN \
-pre VERBOSE
s_client -engine pkcs11 -connect localhost:1443 \
-CAfile $CA \
-keyform engine -key $SLOT:$KID \
-cert $KID.pem
EOM
这很容易翻译成本机代码,只需在应用程序中搜索引擎即可。openssl应用程序中的c。c文件-查看这是如何完成的。在大多数情况下
pkey = ENGINE_load_private_key(e, file,
与旧的相反
BIO_read_filename(key,file)
pkey=d2i_PrivateKey_bio(key, NULL);
我不知道我会将OpenSSL引擎的任何方面描述为“相当简单”。命令行版本很混乱,我只能在自己编写代码后才能知道命令行在做什么。操作顺序和生存期调用得不太好(我仍然不完全知道它们是什么,但我的系统正在运行,不再泄漏内存,所以耶。)
我已经在github上发布了功能版本:https://github.com/tkil/openssl-pkcs11-samples
以下是tok-sign. c
相关部分的导览:
首先,一些帮手:
#define FAIL( msg, dest ) \
do { \
fprintf( stderr, "error: " msg "\n" ); \
goto dest; \
} while ( 0 )
/* mandatory is "not optional"... */
const int CMD_MANDATORY = 0;
动态引擎最奇怪的地方可能是它实际上是一个元引擎:你给它输入各种参数,当你给它输入加载时,它加载动态库,并提供一个新的引擎。一旦知道了正确的操作顺序,代码就很简单了。在这里,我们访问动态引擎,对其进行配置,然后要求它引入pkcs11引擎:
ENGINE_load_dynamic();
ENGINE * dyn = ENGINE_by_id( "dynamic" );
if ( ! dyn )
FAIL( "retrieving 'dynamic' engine", free_out_sig_file );
// this is the bridge between OpenSSL and any generic PCKS11 provider:
char * engine_pkcs11_so = "/opt/crypto/lib/engines/engine_pkcs11.so";
if ( 1 != ENGINE_ctrl_cmd_string( dyn, "SO_PATH", engine_pkcs11_so, CMD_MANDATORY ) )
FAIL( "dyn: setting so_path <= 'engine_pkcs11.so'", free_dyn );
if ( 1 != ENGINE_ctrl_cmd_string( dyn, "ID", "pkcs11", CMD_MANDATORY ) )
FAIL( "dyn: setting id <= 'pkcs11'", free_dyn );
if ( 1 != ENGINE_ctrl_cmd( dyn, "LIST_ADD", 1, NULL, NULL, CMD_MANDATORY ) )
FAIL( "dyn: setting list_add <= 1", free_dyn );
if ( 1 != ENGINE_ctrl_cmd( dyn, "LOAD", 1, NULL, NULL, CMD_MANDATORY ) )
FAIL( "dyn: setting load <= 1", free_dyn );
此时,如果所有这些调用都成功,那么您的OpenSSL实例现在可以访问一个名为“pkcs11”的新引擎。现在,我们需要访问该新引擎,正确配置它,并让它自己初始化:
ENGINE * pkcs11 = ENGINE_by_id( "pkcs11" );
if ( ! pkcs11 )
FAIL( "pkcs11: unable to get engine", free_dyn );
// this is the actual pkcs11 provider we're using. in this case, it's
// from the OpenSC package.
char * opensc_pkcs11_so = "/opt/crypto/lib/opensc-pkcs11.so";
if ( 1 != ENGINE_ctrl_cmd_string( pkcs11, "MODULE_PATH", opensc_pkcs11_so, CMD_MANDATORY ) )
FAIL( "setting module_path <= 'opensc-pkcs11.so'", free_pkcs11 );
if ( 1 != ENGINE_ctrl_cmd_string( pkcs11, "PIN", key_pin, CMD_MANDATORY ) )
FAIL( "setting pin", free_pkcs11 );
if ( 1 != ENGINE_init( pkcs11 ) )
FAIL( "pkcs11: unable to initialize engine", free_pkcs11 );
现在我们可以访问令牌了,我们可以获取用于OpenSSL操作的私钥:
EVP_PKEY * key = ENGINE_load_private_key( pkcs11, key_id, NULL, NULL );
if ( ! key )
FAIL( "reading private key", free_pkcs11 );
但是,我不知道如何通过引擎接口提取相应的证书,所以我直接转到LibP11:
PKCS11_CTX * p11_ctx = PKCS11_CTX_new();
if ( ! p11_ctx )
FAIL( "opening pkcs11 context", free_key );
if ( 0 != PKCS11_CTX_load( p11_ctx, opensc_pkcs11_so ) )
FAIL( "unable to load module", free_p11_ctx );
PKCS11_SLOT * p11_slots;
unsigned int num_p11_slots;
if ( 0 != PKCS11_enumerate_slots( p11_ctx, &p11_slots, &num_p11_slots ) )
FAIL( "enumerating slots", free_p11_ctx_module );
PKCS11_SLOT * p11_used_slot =
PKCS11_find_token( p11_ctx, p11_slots, num_p11_slots );
if ( ! p11_used_slot )
FAIL( "finding token", free_p11_slots );
PKCS11_CERT * p11_certs;
unsigned int num_p11_certs;
if ( 0 != PKCS11_enumerate_certs( p11_used_slot->token, &p11_certs, &num_p11_certs ) )
FAIL( "enumerating certs", free_p11_slots );
最后,我们开始收集CMS\U签名请求的数据。我们查看令牌上的所有证书,找出与私钥对应的证书,然后将其余证书存储在(X509)的OpenSSL堆栈中:
STACK_OF(X509) * extra_certs = sk_X509_new_null();
if ( ! extra_certs )
FAIL( "allocating extra certs", free_p11_slots );
X509 * key_cert = NULL;
for ( unsigned int i = 0; i < num_p11_certs; ++i )
{
PKCS11_CERT * p11_cert = p11_certs + i;
if ( ! p11_cert->label )
continue;
// fprintf( stderr, "p11: got cert label='%s', x509=%p\n",
// p11_cert->label, p11_cert->x509 );
if ( ! p11_cert->x509 )
{
fprintf( stderr, "p11: ... no x509, ignoring\n" );
continue;
}
const char * label = p11_cert->label;
const unsigned int label_len = strlen( label );
if ( strcmp( label, key_label ) == 0 )
{
// fprintf( stderr, "p11: ... saving as signing cert\n" );
key_cert = p11_cert->x509;
}
else if ( strncmp( label, "encrypt", 7 ) == 0 &&
label_len == 8 &&
'0' <= label[7] && label[7] <= '3' )
{
// fprintf( stderr, "p11: ... ignoring as encrypting cert\n" );
}
else
{
// fprintf( stderr, "p11: ... saving as extra cert\n" );
if ( ! sk_X509_push( extra_certs, p11_cert->x509 ) )
FAIL( "pushing extra cert", free_extra_certs );
}
}
if ( ! key_cert )
FAIL( "finding signing cert", free_extra_certs );
最后,我们可以对数据进行签名,然后将签名输出到DER格式的文件中:
CMS_ContentInfo * ci = CMS_sign( key_cert, key, extra_certs, in_data_file,
CMS_DETACHED | CMS_BINARY );
if ( ! ci )
FAIL( "could not create signing structure", free_extra_certs );
if ( 1 != i2d_CMS_bio( out_sig_file, ci ) )
FAIL( "could not write signature in DER", free_ci );
之后就是清理:
free_ci:
CMS_ContentInfo_free( ci );
free_extra_certs:
/* these certs are actually "owned" by the libp11 code, and are
* presumably freed with the slot or context. */
sk_X509_free( extra_certs );
free_p11_slots:
PKCS11_release_all_slots( p11_ctx, p11_slots, num_p11_slots );
free_p11_ctx_module:
PKCS11_CTX_unload( p11_ctx );
free_p11_ctx:
PKCS11_CTX_free( p11_ctx );
free_key:
EVP_PKEY_free( key );
free_pkcs11:
ENGINE_free( pkcs11 );
free_dyn:
ENGINE_free( dyn );
null null null 多谢!
我正在编写一个Java程序,该程序使用USB证书(智能卡)进行加密和签名。我有一个共享库(Windows上为.dll,Linux上为.so),它为硬件实现PKCS11。 我正在搜索现有的解决方案,并找到以下指南http://docs.oracle.com/javase/7/docs/technotes/guides/security/p11guide.html指南建议使用sun。安全pkcs11.
我正在开发一个功能来对某些内容进行数字签名。我有一个带有私钥的有效证书。如何使用私钥和充气城堡进行数字签名? 我尝试了以下方法,但想要一些正确的方法来实现同样的使用充气城堡: 谢谢!
我想在客户端设备上使用通过Ed25519生成的私钥对JWS(json web签名)进行签名。然后将这个签名发送到我的后端,并用公钥验证它。为了熟悉这个过程,我想尝试在node js中对JWS进行签名和验证 我的私钥和公钥都已生成,可以在base58中使用。这是我目前使用Ed25519私钥签署JWT的尝试: 密钥必须是KeyObject或CryptoKey类型之一。收到一个Uint8Array的实例
问题内容: 我正在做。 我使用keytool创建了CSR,该工具已向密钥库添加了私钥, 收到基于CSR的证书,将证书转换为DER格式,并将证书作为trustcacerts导入密钥库 签名证书在证书路径中具有根/中间证书 在将根证书和中间证书转换为DER格式后,我还在受信任的根证书下安装了IE的根证书和中间证书。 使用https时,浏览器显示证书错误,并将该证书视为自签名证书。 题 这是否意味着由于
我正在通过PKI开发身份验证。我是通过PKI认证用户的新手,所以在网上阅读后,我想出了这个解决方案。用户将创建公钥和私钥。为了验证公钥,用户将申请数字证书。数字证书将具有公钥、用户的元数据和证书颁发机构的数字签名。为了证明没有数据被篡改,用户将使用数字签名,这将是证书与用户私钥的哈希。用户将向服务器发送数字证书、数字签名和数据。 作为响应,服务器将验证数字证书并获取公钥以验证数字签名,验证后,服务