私は次のことをしたい:
- セキュリティ トークンでキー ペアを生成します (私は Aladdin トークンを使用します) (PyKCS11)
- PKCS#10 リクエスト (私は M2Crypto + engine_pkcs11 を使用) を生成し、CA に送信します。
- CA から署名付き X.509 証明書を受け取り、セキュリティ トークンに書き込みます。
リクエストの生成は次のように行われます。
def generate_request(
self, uid, cn=None, user_pin=None, keyid=TOKEN_TEMP_KEY_ID):
"""Generate PKCS#10 certificate request
@param keyid: ID of key to use for certificate request generation
@type keyid: str
@param uid: UID to put in request subject distinguished name
@type uid: str
@param cn: Common name (if any) of subject to use for certificate
request generation
@type cn: str
@param user_pin: user PIN code. User privileges are required for
signing of certificate request
@type user_pin: str
@return PKCS10 request in PEM format signed by token's private key
"""
Engine.load_dynamic()
e = Engine.Engine('dynamic')
e.ctrl_cmd_string('SO_PATH', PKCS11_ENGINE_PATH)
e.ctrl_cmd_string('LIST_ADD', '1')
e.ctrl_cmd_string('LOAD', None)
e.ctrl_cmd_string('MODULE_PATH', PKCS11_LIBRARY_PATH)
a = Engine.Engine('pkcs11')
a.init()
# Hex-encoded key id should be provided to that function
k = a.load_private_key(hexlify(keyid), pin=user_pin)
req = X509.Request()
subject_name = PKCS10_DN_PREFIX + (('UID', MBSTRING_ASC, uid, -1, -1, 0),)
if cn:
subject_name = subject_name + (('CN', MBSTRING_ASC, cn, -1, -1, -1),)
name = X509.X509_Name()
for entry in subject_name:
name.add_entry_by_txt(*entry)
req.set_subject(name)
req.set_pubkey(k)
req.sign(k, 'sha1')
reqpem = req.as_pem()
Engine.cleanup()
return reqpem
証明書をセキュリティ トークンに書き込むコードは次のとおりです。
def write_certificate(self, cert_pem, so_pin):
"""Write certificate to token
@param cert_pem: certificate in pem format
@type cert_pem: str
@param so_pin: PIN code of security officer
@type so_pin: str
"""
cert = X509.load_cert_string(cert_pem)
if cert.check_ca(): # What label to use?
label = TOKEN_CA_CERT_LABEL
else:
label = TOKEN_USER_CERT_LABEL
tCert = (
(PyKCS11.LowLevel.CKA_CLASS, PyKCS11.LowLevel.CKO_CERTIFICATE),
(PyKCS11.LowLevel.CKA_CERTIFICATE_TYPE, PyKCS11.LowLevel.CKC_X_509),
(PyKCS11.LowLevel.CKA_TOKEN, True),
(PyKCS11.LowLevel.CKA_PRIVATE, False),
(PyKCS11.LowLevel.CKA_LABEL, label),
(PyKCS11.LowLevel.CKA_ID, make_key_id(cert.get_pubkey())),
(PyKCS11.LowLevel.CKA_SUBJECT, cert.get_subject().as_der()),
(PyKCS11.LowLevel.CKA_ISSUER, cert.get_issuer().as_der()),
(PyKCS11.LowLevel.CKA_SERIAL_NUMBER, cert.get_serial_number()),
(PyKCS11.LowLevel.CKA_VALUE, cert.as_der()))
s = self.lib.openSession(self.slot, PyKCS11.CKF_RW_SESSION)
s.login(so_pin, PyKCS11.LowLevel.CKU_SO)
s.createObject(tCert)
s.logout()
s.closeSession()
問題は、リクエストの生成後に CKR_USER_ANOTHER_ALREADY_LOGGED_IN エラーが発生することです。engine_pkcs11 のソース コードを調べたところ、engine_pkcs11.c (https://github.com/OpenSC/engine_pkcs11/blob/master/src/engine_pkcs11.c) ファイルに という関数がありましたstatic EVP_PKEY *pkcs11_load_key
。かなり長いのでその一部を以下に示します。
/* Now login in with the (possibly NULL) pin */
if (PKCS11_login(slot, 0, pin)) {
/* Login failed, so free the PIN if present */
if (pin != NULL) {
OPENSSL_cleanse(pin, pin_length);
free(pin);
pin = NULL;
pin_length = 0;
}
fail("Login failed\n");
}
そのため、キーが使用されたときにログインが実行されることを理解しています(PKCS#10リクエスト生成にはキーが必要です)。ログインが実行された場合、対応するログアウトも実行する必要があると思いますが、見つかりませんでした。ENGINE_finish() 関数のソースは次のとおりです。
int pkcs11_finish(ENGINE * engine)
{
if (ctx) {
PKCS11_CTX_unload(ctx);
PKCS11_CTX_free(ctx);
ctx = NULL;
}
if (pin != NULL) {
OPENSSL_cleanse(pin, pin_length);
free(pin);
pin = NULL;
pin_length = 0;
}
return 1;
}
ステップ2でセキュリティトークンからログアウトすることは可能ですか?