- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在寻找对给定文件进行签名并获得 CMS 格式输出的最简单方法,但这必须使用 PKCS11 提供程序,因为用于签名的私钥位于智能卡上。
我可以使用 openssl 从命令行获取正确格式的签名文件(但请注意,这是从文件而不是智能卡获取证书)
openssl cms -sign -in sign.txt -out signout.txt -signer signer.pem -outform DER
我想使用尽可能最薄的包装器从代码中做到这一点。我可以使用 openssl 库,但要支持 pkcs11,您需要通过引擎连接(opensc 有一个),但随后它开始变得非常大。我突然想到一定有一个简单的 PKCS11 包装器可以在某处使用。
如果包装器在“C”或 .net 中,我很高兴。我可以自己调用 PKCS11 提供程序并进行签名,如果我知道如何输出为 CMS 那么也许一个库就足够了?
最美好的祝愿詹姆斯
最佳答案
参加晚会已经很晚了(黑客同行们 2 年算什么?),但这是我的“最小”OpenSSL + PKCS11 签名程序(用 C99 编写,通过将所有变量定义移至 block 顶部可转换为 C89) .
就我而言,我在/opt/crypto 中“手动”构建了一个自定义加密堆栈,该程序的链接行是:
gcc -o tok-sign tok-sign.c -I /opt/crypto/include -g --std=gnu99 -Wall \
-L/opt/crypto/lib -lssl -lcrypto -lrt -lp11
最奇怪的是理解“动态”引擎真的应该被称为“元引擎”;而且我必须直接通过 libp11 接口(interface)获取证书以传递到 CMS_sign
操作中。
它可以使用更多评论,而且它很长;我为两者道歉。基本要点是:
动态
元引擎加载pkcs11
引擎pkcs1
1 引擎以使用 opensc pkcs11 提供程序libp11
从 token 中读取额外的证书CMS_sign
完成繁重的工作这是程序本身。我可能应该把它变成一篇博客文章。
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <openssl/cms.h>
#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <libp11.h>
#define FAIL( msg, dest ) \
do { \
fprintf( stderr, "error: " msg "\n" ); \
goto dest; \
} while ( 0 )
static
void
print_time( const char * label )
{
struct timespec ts;
clock_gettime( CLOCK_MONOTONIC, &ts );
fprintf( stderr, "+%8lld.%09ld: %s\n",
(long long)ts.tv_sec, ts.tv_nsec, label );
}
int
main( int argc, char * argv [] )
{
enum
{
ARG_IN_DATA_FILE_IX = 1,
ARG_OUT_SIG_FILE_IX = 2,
ARG_KEY_LABEL_IX = 3,
ARG_KEY_PIN_IX = 4
};
int exit_code = 0;
/* -------------------------------------------------------------- */
/* initialization */
exit_code = 1;
SSL_load_error_strings();
SSL_library_init();
/* -------------------------------------------------------------- */
/* command-line processing */
exit_code = 2;
if ( argc != 5 )
{
fprintf( stderr, "usage: %s IN_DATA_FILE OUT_SIG_FILE"
" KEY_LABEL KEY_PIN\n", argv[0] );
return 1;
}
BIO * in_data_file = BIO_new_file( argv[ ARG_IN_DATA_FILE_IX ], "rb" );
if ( ! in_data_file )
{
perror( argv[ ARG_IN_DATA_FILE_IX ] );
goto end;
}
BIO * out_sig_file = BIO_new_file( argv[ ARG_OUT_SIG_FILE_IX ], "wb" );
if ( ! out_sig_file )
{
perror( argv[ ARG_OUT_SIG_FILE_IX ] );
goto free_in_data_file;
}
const char * key_label = argv[ ARG_KEY_LABEL_IX ];
char * key_id = calloc( sizeof( char ), strlen( key_label ) + 7 );
strcpy( key_id, "label_" );
strcat( key_id, key_label );
const char * key_pin = argv[ ARG_KEY_PIN_IX ];
/* -------------------------------------------------------------- */
/* load dynamic modules / engines */
exit_code = 3;
/* mandatory is "not optional"... */
const int CMD_MANDATORY = 0;
ENGINE_load_dynamic();
ENGINE * pkcs11 = ENGINE_by_id( "dynamic" );
if ( ! pkcs11 )
FAIL( "retrieving 'dynamic' engine", free_out_sig_file );
char * engine_pkcs11_so = "/opt/crypto/lib/engines/engine_pkcs11.so";
if ( 0 != access( engine_pkcs11_so, R_OK ) )
{
engine_pkcs11_so = "/lib/engines/engine_pkcs11.so";
if ( 0 != access( engine_pkcs11_so, R_OK ) )
FAIL( "finding 'engine_pkcs11.so'", free_pkcs11 );
}
if ( 1 != ENGINE_ctrl_cmd_string( pkcs11, "SO_PATH", engine_pkcs11_so, CMD_MANDATORY ) )
FAIL( "pkcs11: setting so_path <= 'engine_pkcs11.so'", free_pkcs11 );
if ( 1 != ENGINE_ctrl_cmd_string( pkcs11, "ID", "pkcs11", CMD_MANDATORY ) )
FAIL( "pkcs11: setting id <= 'pkcs11'", free_pkcs11 );
if ( 1 != ENGINE_ctrl_cmd( pkcs11, "LIST_ADD", 1, NULL, NULL, CMD_MANDATORY ) )
FAIL( "pkcs11: setting list_add <= 1", free_pkcs11 );
if ( 1 != ENGINE_ctrl_cmd( pkcs11, "LOAD", 1, NULL, NULL, CMD_MANDATORY ) )
FAIL( "pkcs11: setting load <= 1", free_pkcs11 );
ENGINE * tok = ENGINE_by_id( "pkcs11" );
if ( ! tok )
FAIL( "tok: unable to get engine", free_pkcs11 );
char * opensc_pkcs11_so = "/opt/crypto/lib/opensc-pkcs11.so";
if ( 0 != access( opensc_pkcs11_so, R_OK ) )
{
opensc_pkcs11_so = "/lib/opensc-pkcs11.so";
if ( 0 != access( opensc_pkcs11_so, R_OK ) )
FAIL( "finding 'opensc-pkcs11.so'", free_tok );
}
if ( 1 != ENGINE_ctrl_cmd_string( tok, "MODULE_PATH", opensc_pkcs11_so, CMD_MANDATORY ) )
FAIL( "setting module_path <= 'opensc-pkcs11.so'", free_tok );
if ( 1 != ENGINE_ctrl_cmd_string( tok, "PIN", key_pin, CMD_MANDATORY ) )
FAIL( "setting pin", free_tok );
if ( 1 != ENGINE_init( tok ) )
FAIL( "tok: unable to initialize engine", free_tok );
/* -------------------------------------------------------------- */
/* reading from token */
exit_code = 4;
EVP_PKEY * key = ENGINE_load_private_key( tok, key_id, NULL, NULL );
if ( ! key )
FAIL( "reading private key", free_tok );
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 );
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 );
/* -------------------------------------------------------------- */
/* signing */
exit_code = 5;
print_time( "calling CMS_sign" );
CMS_ContentInfo * ci = CMS_sign( key_cert, key, extra_certs, in_data_file,
CMS_DETACHED | CMS_BINARY );
/* if ( 1 != PEM_write_bio_CMS( out_sig_file, ci ) )
FAIL( "could not write signature in PEM", free_ci ); */
print_time( "calling i2d_CMS_bio" );
if ( 1 != i2d_CMS_bio( out_sig_file, ci ) )
FAIL( "could not write signature in DER", free_ci );
print_time( "done" );
/* -------------------------------------------------------------- */
/* success */
exit_code = 0;
/* -------------------------------------------------------------- */
/* cleanup */
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_tok:
ENGINE_free( tok );
free_pkcs11:
ENGINE_free( pkcs11 );
free_out_sig_file:
BIO_vfree( out_sig_file );
free_in_data_file:
BIO_vfree( in_data_file );
ERR_print_errors_fp( stderr );
ERR_remove_state( /* pid= */ 0 );
ENGINE_cleanup();
CONF_modules_unload( /* all= */ 1 );
EVP_cleanup();
ERR_free_strings();
CRYPTO_cleanup_all_ex_data();
end:
return exit_code;
}
关于.net - 使用 PKCS11 提供程序对文件进行加密签名并以 CMS 格式输出的最简单方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6598801/
有没有办法使用 Clojure format(基于 java.util.Formatter)或 cl-format(基于 Common Lisp 的format) 以编程方式设置空格填充?如果您事先知
我正在尝试创建一个用户实体以及数据/文件(pdf格式)。上传并保存到数据库很好,但是当我让用户进入 postman 时尝试发送获取请求方法,然后在数据字段中显示一些糟糕的数据,而且我无法在数据库中看到
我必须将值为 {"STX","ETX"} 的普通字符串数组转换为十六进制值,并且我应该根据 http://www.asciitable.com/ 得到 {2,3} . 最佳答案 听起来你想要一个 Ma
我想格式化我的代码,但不确定哪种格式类型最适合我的项目需要。 我发现仅对于 dart 和 flutter 项目(我都有),有不止一个选项可用于格式化编程语言/框架中预先构建的代码。 Dart : da
我已经尝试了多个代码,例如这样 Sub DateFixer() Application.ScreenUpdating = False Application.Calculation =
SolrQuery query = new SolrQuery(); query.setQuery("*:*"); query.add("wt","csv"); server.query(query)
我有一个包含多个字符串的数据库,我从查询中获取了这些记录,并且我在 QString 中收到了这种格式的数据: "Mon, 13 Nov 2017 09:48:45 +0000" 所以,我需要根据文化来
我有一个 Delphi 2007 DBGrid,我想让用户以更新的 Excel 格式 (OOXML) 保存它,但我的标准是用户不需要安装 Excel。有没有人知道任何已经这样做的组件?是的,我已经搜索
我正在我们的普通 html 站点旁边创建一个移动站点。使用 rails 3.1。移动站点在子域 m.site.com 中访问。 我已经定义了移动格式(Mime::Type.register_alias
我正在尝试使用 xmlstarlet 格式化 xml 文件,但我不想创建新的 xml 文件。 我试过了 xmlstarlet fo --inplace --indent-tab --omit-decl
我在 A 列中有一个带有文本的电子表格。 例如 A1=MY TEXT1 A2=MY TEXT2 A3=MY TEXT3 A4=MY TEXT4 A5=MY TEXT5 我想在文本的前后添加撇号 结果是
我想做一些源代码转换(自动导入列表清理),我想保留注释和格式。我听说过一些关于解析器这样做的事情,我认为是 ghc 解析器。 看起来我可以通过从文件中提取内容来使用 hs-src-exts Langu
我在 Excel 中工作,我想根据另一张表中的列表找出一张表中是否有匹配项。 我已将值粘贴到列表中,并希望从另一张表中返回它们的相应值。包含字母和数字的单元格可以正常工作(例如:D5765000),但
我有一个 DurationField在我的模型中定义为 day0 = models.DurationField('Duration for Monday', default=datetime.time
我正在为我的应用程序开发 WMI 查询。它需要为给定的 VID/PID 找到分配的虚拟 COM 端口。使用 WMI Code Creator 我发现...... 命名空间:root\CIMV2 类:W
我试图弄清楚如何使用 NSTextList,但除了 this SO question 之外,在网上几乎没有找到有用的信息。和 the comment in this blog . 使用这个我已经能够创
我要查询all_objects表在哪里last_ddl_time='01 jan 2010'但它拒绝日期格式... 任何机构给我查询的确切格式? 最佳答案 正如 AKF 所说,您应该使用 Trunc除
我试图在我的应用程序中实现聊天功能。我使用了 2 个 JEditorPane。一个用于保存聊天记录,另一个用于将聊天发送到前一个 JEditorPane。 JEditorPane 是 text/h
我在大学里修了一个编译器类(class),内容非常丰富,很有趣,尽管也很多工作。既然给了我们要实现的语言规范,所以我学不到的一件事就是语言设计。我现在正在考虑创建一种有趣的简单玩具语言,以便我可以玩耍
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic
我是一名优秀的程序员,十分优秀!