2011-07-06 77 views
3

我正在尋找簽署給定文件並以CMS格式獲取輸出的最簡單方法,但是這必須使用PKCS11提供程序,因爲用於簽名的私鑰位於智能卡上。使用PKCS11提供程序對CMS文件進行加密簽名和輸出的最簡單方法?

我可以從OpenSSL的命令行格式正確的簽名文件(但要注意這正從一個文件中的證書,而不是智能卡)

openssl cms -sign -in sign.txt -out signout.txt -signer signer.pem -outform DER

我想這樣做這從代碼使用最薄的包裝可能。我可以使用openssl庫,但是爲了支持pkcs11,你需要通過引擎進行連接(opensc有一個),但是它開始變得非常大。它讓我覺得必須有一個簡單的PKCS11包裝器。

如果包裝是'C'或.net,我很高興。 我可以自己調用PKCS11提供程序,並進行簽名,如果我知道如何輸出爲CMS,那麼也許一個庫來執行此操作就足夠了?

祝 詹姆斯

+0

如果你不介意的商業解決方案,我們的SecureBlackbox(http://www.eldos.com/sbb/net-pki.php)會做你需要的代碼行的打什麼。另一種方法可能是編寫自己的CMS實現。 –

+0

你是什麼意思,開始變得很大?你真的想要解決什麼樣的問題?在我看來,如果要保持輕量級,在OpenSSL下推出預製的PKCS#11模塊就是完成工作的方式。你使用智能卡獲得了哪些資源? –

+0

在分配方面變得非常大。該卡有pkcs11驅動程序,所以很好。從命令行Openssl不能使用引擎簽名使用智能卡,但可能從代碼(尚未嘗試),但我需要openssl和引擎鏈接到我的應用程序 –

回答

0

我寫了一套房PKCS7簽署/加密工具而回,這裏是一個片段可以幫助(C#.NET 3.5):

private byte[] signFile(byte[] fileContent, X509Certificate2 verificationCert) 
{ 
    ContentInfo contentInfo = new ContentInfo(fileContent);   
    SignedCms signedCMS = new SignedCms(contentInfo); 
    CmsSigner cmsSigner = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, verificationCert); 
    cmsSigner.SignedAttributes.Add(new Pkcs9SigningTime()); 
    signedCMS.ComputeSignature(cmsSigner, false); 
    byte[] encoded = signedCMS.Encode(); 

    return encoded; 
} 

我寫了簽名的內容到.p7m文件。我不知道你如何修改這個以適應你的智能卡,我不得不更多地瞭解它。

+0

不幸的是,標準.net CMS功能依賴於Windows證書存儲。卡上的私鑰不可用,我需要通過PKCS11 API –

3

這次派對非常晚(在同伴黑客中有2年?),但這裏是我的「最小」OpenSSL + PKCS11簽名程序(用C99編寫,可轉換爲C89,將所有變量定義移動到塊頂部)。

在我的情況,我在/ opt /加密建立了一個自定義的加密堆棧「手動」,並且此程序的鏈接線:

gcc -o tok-sign tok-sign.c -I /opt/crypto/include -g --std=gnu99 -Wall \ 
    -L/opt/crypto/lib -lssl -lcrypto -lrt -lp11 

最奇怪位被理解的是,「動態」引擎真的應該被稱爲「元引擎」;而且我必須直接通過libp11接口才能將證書傳遞到CMS_sign操作中。

它可以使用更多的評論,並且它很長;我爲兩人道歉。的基本要點是:

  1. 初始化的OpenSSL
  2. 處理命令行參數(輸入,輸出,鍵標籤,令牌PIN)
  3. 配置dynamic元發動機加載pkcs11發動機
  4. 配置在pkcs1 1引擎來使用通過opensc PKCS11提供商
  5. 閱讀的額外證書關令牌libp11
  6. 使用OpenSSL的CMS_sign做繁重的工作
  7. 發出DER格式的結果簽名
  8. 做清理所需的許多不同位。

這是程序本身。我應該把它變成一個博客文章。

#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; 
} 
+0

進行訪問,您應該馬上或稍後寫這篇文章.. :)這裏的文檔太少了。謝謝! –

相關問題