1 # Copyright (C) Internet Systems Consortium, Inc. ("ISC") 2 # 3 # SPDX-License-Identifier: MPL-2.0 4 # 5 # This Source Code Form is subject to the terms of the Mozilla Public 6 # License, v. 2.0. If a copy of the MPL was not distributed with this 7 # file, you can obtain one at https://mozilla.org/MPL/2.0/. 8 # 9 # See the COPYRIGHT file distributed with this work for additional 10 # information regarding copyright ownership. 11 12 import hashlib 13 import os 14 from re import compile as Re 15 import shutil 16 17 import pytest 18 19 import isctest.mark 20 21 22 pytestmark = [ 23 isctest.mark.softhsm2_environment, 24 pytest.mark.extra_artifacts( 25 [ 26 "*.example.db", 27 "*.example.db.signed", 28 "K*", 29 "dsset-*", 30 "keyfromlabel.out.*", 31 "pin", 32 "pkcs11-tool.out.*", 33 "signer.out.*", 34 ], 35 ), 36 ] 37 38 39 EMPTY_OPENSSL_CONF_ENV = {**os.environ, "OPENSSL_CONF": ""} 40 41 HSMPIN = "1234" 42 43 44 @pytest.fixture(autouse=True) 45 def token_init_and_cleanup(): 46 47 # Create pin file for the $KEYFRLAB command 48 with open("pin", "w", encoding="utf-8") as pinfile: 49 pinfile.write(HSMPIN) 50 51 token_init_command = [ 52 "softhsm2-util", 53 "--init-token", 54 "--free", 55 "--pin", 56 HSMPIN, 57 "--so-pin", 58 HSMPIN, 59 "--label", 60 "softhsm2-keyfromlabel", 61 ] 62 63 token_cleanup_command = [ 64 "softhsm2-util", 65 "--delete-token", 66 "--token", 67 "softhsm2-keyfromlabel", 68 ] 69 70 isctest.run.cmd( 71 token_cleanup_command, 72 env=EMPTY_OPENSSL_CONF_ENV, 73 raise_on_exception=False, 74 ) 75 76 try: 77 cmd = isctest.run.cmd(token_init_command, env=EMPTY_OPENSSL_CONF_ENV) 78 assert "The token has been initialized and is reassigned to slot" in cmd.out 79 yield 80 finally: 81 cmd = isctest.run.cmd( 82 token_cleanup_command, 83 env=EMPTY_OPENSSL_CONF_ENV, 84 raise_on_exception=False, 85 ) 86 assert Re("Found token (.*) with matching token label") in cmd.out 87 88 89 # pylint: disable-msg=too-many-locals 90 @pytest.mark.parametrize( 91 "alg_name,alg_type,alg_bits", 92 [ 93 ("rsasha256", "rsa", "2048"), 94 ("rsasha512", "rsa", "2048"), 95 ("ecdsap256sha256", "EC", "prime256v1"), 96 ("ecdsap384sha384", "EC", "prime384v1"), 97 # Edwards curves are not yet supported by OpenSC 98 # ("ed25519","EC","edwards25519"), 99 # ("ed448","EC","edwards448") 100 ], 101 ) 102 def test_keyfromlabel(alg_name, alg_type, alg_bits): 103 104 def keygen(alg_type, alg_bits, zone, key_id): 105 label = f"{key_id}-{zone}" 106 p11_id = hashlib.sha1(label.encode("utf-8")).hexdigest() 107 108 pkcs11_command = [ 109 "pkcs11-tool", 110 "--module", 111 os.environ.get("SOFTHSM2_MODULE"), 112 "--token-label", 113 "softhsm2-keyfromlabel", 114 "-l", 115 "-k", 116 "--key-type", 117 f"{alg_type}:{alg_bits}", 118 "--label", 119 label, 120 "--id", 121 p11_id, 122 "--pin", 123 HSMPIN, 124 ] 125 126 cmd = isctest.run.cmd(pkcs11_command, env=EMPTY_OPENSSL_CONF_ENV) 127 128 assert "Key pair generated" in cmd.out 129 130 def keyfromlabel(alg_name, zone, key_id, key_flag): 131 key_flag = key_flag.split() if key_flag else [] 132 133 keyfrlab_command = [ 134 os.environ["KEYFRLAB"], 135 *os.environ.get("ENGINE_ARG", "").split(), 136 "-a", 137 alg_name, 138 "-y", 139 "-l", 140 f"pkcs11:token=softhsm2-keyfromlabel;object={key_id}-{zone};pin-source=pin", 141 *key_flag, 142 zone, 143 ] 144 145 cmd = isctest.run.cmd(keyfrlab_command) 146 keyfile = cmd.out.rstrip() + ".key" 147 148 assert os.path.exists(keyfile) 149 150 return keyfile 151 152 if f"{alg_name.upper()}_SUPPORTED" not in os.environ: 153 pytest.skip(f"{alg_name} is not supported") 154 155 # Generate keys for the $zone zone 156 zone = f"{alg_name}.example" 157 158 keygen(alg_type, alg_bits, zone, "keyfromlabel-zsk") 159 keygen(alg_type, alg_bits, zone, "keyfromlabel-ksk") 160 161 # Get ZSK 162 zsk_file = keyfromlabel(alg_name, zone, "keyfromlabel-zsk", "") 163 164 # Get KSK 165 ksk_file = keyfromlabel(alg_name, zone, "keyfromlabel-ksk", "-f KSK") 166 167 # Sign zone with KSK and ZSK 168 zone_file = f"zone.{alg_name}.example.db" 169 170 with open(zone_file, "w", encoding="utf-8") as outfile: 171 for f in ["template.db.in", ksk_file, zsk_file]: 172 with open(f, "r", encoding="utf-8") as fd: 173 shutil.copyfileobj(fd, outfile) 174 175 signer_command = [ 176 os.environ["SIGNER"], 177 *os.environ.get("ENGINE_ARG", "").split(), 178 "-S", 179 "-a", 180 "-g", 181 "-o", 182 zone, 183 zone_file, 184 ] 185 isctest.run.cmd(signer_command) 186 187 assert os.path.exists(f"{zone_file}.signed") 188