1 /* $NetBSD: pkcs11-hmacmd5.c,v 1.1.1.4 2014/12/10 03:34:28 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Portions copyright (c) 2008 Nominet UK. All rights reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the above copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 34 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 40 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 */ 42 43 /* Id */ 44 45 /* 46 * pkcs11-hmacmd5 47 * 48 * Prints the MD5 HMAC of the standard input, using the PKCS#11 device. 49 * 50 * Usage: 51 * pkcs11-hmacmd5 [-m module] [-s $slot] [-n] [-p $pin] 52 * -m: PKCS#11 provider module. This must be the full 53 * path to a shared library object implementing the 54 * PKCS#11 API for a device. 55 * -s: Slot 56 * -p: PIN 57 * -n: don't log in to the PKCS#11 device 58 * -k: key name for the HMAC 59 */ 60 61 /*! \file */ 62 63 #include <config.h> 64 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <fcntl.h> 68 #include <errno.h> 69 #include <string.h> 70 #include <sys/types.h> 71 72 #include <isc/commandline.h> 73 #include <isc/result.h> 74 #include <isc/types.h> 75 76 #include <pk11/pk11.h> 77 #include <pk11/result.h> 78 79 #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) 80 #define getpassphrase(x) getpass(x) 81 #endif 82 83 /* Define static key template values */ 84 static CK_BBOOL truevalue = TRUE; 85 static CK_BBOOL falsevalue = FALSE; 86 87 #define BLOCKSIZE 32768 88 89 char buffer[BLOCKSIZE + 72]; 90 char digest[16]; 91 92 int 93 main(int argc, char *argv[]) { 94 isc_result_t result; 95 CK_RV rv; 96 CK_SLOT_ID slot = 0; 97 CK_SESSION_HANDLE hSession; 98 CK_MECHANISM mech = { CKM_MD5_HMAC, NULL, 0 }; 99 CK_ULONG len; 100 CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; 101 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; 102 CK_KEY_TYPE keyType = CKK_MD5_HMAC; 103 CK_ATTRIBUTE keyTemplate[] = 104 { 105 { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, 106 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, 107 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 108 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 109 { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, 110 { CKA_VALUE, NULL, 0 } 111 }; 112 pk11_context_t pctx; 113 pk11_optype_t op_type = OP_DIGEST; 114 char *lib_name = NULL; 115 char *pin = NULL; 116 int error = 0; 117 isc_boolean_t logon = ISC_TRUE; 118 int c, errflg = 0; 119 char *key = NULL; 120 size_t sum = 0; 121 unsigned int i; 122 123 while ((c = isc_commandline_parse(argc, argv, ":m:s:np:k:")) != -1) { 124 switch (c) { 125 case 'm': 126 lib_name = isc_commandline_argument; 127 break; 128 case 's': 129 slot = atoi(isc_commandline_argument); 130 op_type = OP_ANY; 131 break; 132 case 'n': 133 logon = ISC_FALSE; 134 break; 135 case 'p': 136 pin = isc_commandline_argument; 137 break; 138 case 'k': 139 key = isc_commandline_argument; 140 break; 141 case ':': 142 fprintf(stderr, 143 "Option -%c requires an operand\n", 144 isc_commandline_option); 145 errflg++; 146 break; 147 case '?': 148 default: 149 fprintf(stderr, "Unrecognised option: -%c\n", 150 isc_commandline_option); 151 errflg++; 152 } 153 } 154 155 if (errflg || (key == NULL)) { 156 fprintf(stderr, "Usage:\n"); 157 fprintf(stderr, 158 "\tpkcs11-hmacmd5 [-m module] [-s slot] " 159 "[-n|-p pin] -k key\n"); 160 exit(1); 161 } 162 163 /* Decode the key */ 164 for (i = 0; i < BLOCKSIZE / 2; i++) { 165 switch (c = *key++) { 166 case 0: 167 goto key_done; 168 case '0': 169 case '1': 170 case '2': 171 case '3': 172 case '4': 173 case '5': 174 case '6': 175 case '7': 176 case '8': 177 case '9': 178 if ((i & 1) == 0) 179 buffer[i >> 1] = (c - '0') << 4; 180 else 181 buffer[i >> 1] |= c - '0'; 182 break; 183 case 'A': 184 case 'B': 185 case 'C': 186 case 'D': 187 case 'E': 188 case 'F': 189 if ((i & 1) == 0) 190 buffer[i >> 1] = (c - 'A' + 10) << 4; 191 else 192 buffer[i >> 1] |= c - 'A' + 10; 193 break; 194 case 'a': 195 case 'b': 196 case 'c': 197 case 'd': 198 case 'e': 199 case 'f': 200 if ((i & 1) == 0) 201 buffer[i >> 1] = (c - 'a' + 10) << 4; 202 else 203 buffer[i >> 1] |= c - 'a' + 10; 204 break; 205 default: 206 fprintf(stderr, "Not hexdigit '%c' in key\n", c); 207 exit(1); 208 } 209 } 210 key_done: 211 if ((i & 1) != 0) { 212 fprintf(stderr, "Even number of hexdigits in key\n"); 213 exit(1); 214 } 215 len = i >> 1; 216 keyTemplate[5].pValue = buffer; 217 keyTemplate[5].ulValueLen = (CK_ULONG) len; 218 219 pk11_result_register(); 220 221 /* Initialize the CRYPTOKI library */ 222 if (lib_name != NULL) 223 pk11_set_lib_name(lib_name); 224 225 if (logon && pin == NULL) 226 pin = getpassphrase("Enter Pin: "); 227 228 result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE, logon, 229 (const char *) pin, slot); 230 if ((result != ISC_R_SUCCESS) && 231 (result != PK11_R_NORANDOMSERVICE) && 232 (result != PK11_R_NOAESSERVICE)) { 233 fprintf(stderr, "Error initializing PKCS#11: %s\n", 234 isc_result_totext(result)); 235 exit(1); 236 } 237 238 if (pin != NULL) 239 memset(pin, 0, strlen((char *)pin)); 240 241 hSession = pctx.session; 242 243 rv = pkcs_C_CreateObject(hSession, keyTemplate, (CK_ULONG) 6, &hKey); 244 if (rv != CKR_OK) { 245 fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv); 246 error = 1; 247 goto exit_session; 248 } 249 if (hKey == CK_INVALID_HANDLE) { 250 fprintf(stderr, "C_CreateObject failed\n"); 251 error = 1; 252 goto exit_session; 253 } 254 255 rv = pkcs_C_SignInit(hSession, &mech, hKey); 256 if (rv != CKR_OK) { 257 fprintf(stderr, "C_SignInit: Error = 0x%.8lX\n", rv); 258 error = 1; 259 goto exit_sign; 260 } 261 262 for (;;) { 263 size_t n; 264 265 for (;;) { 266 n = fread(buffer + sum, 1, BLOCKSIZE - sum, stdin); 267 sum += n; 268 if (sum == BLOCKSIZE) 269 break; 270 if (n == 0) { 271 if (ferror(stdin)) { 272 fprintf(stderr, "fread failed\n"); 273 error = 1; 274 goto exit_sign; 275 } 276 goto partial_block; 277 } 278 if (feof(stdin)) 279 goto partial_block; 280 } 281 282 rv = pkcs_C_SignUpdate(hSession, (CK_BYTE_PTR) buffer, 283 (CK_ULONG) BLOCKSIZE); 284 if (rv != CKR_OK) { 285 fprintf(stderr, 286 "C_SignUpdate: Error = 0x%.8lX\n", 287 rv); 288 error = 1; 289 goto exit_sign; 290 } 291 } 292 293 partial_block: 294 if (sum > 0) { 295 rv = pkcs_C_SignUpdate(hSession, (CK_BYTE_PTR) buffer, 296 (CK_ULONG) sum); 297 if (rv != CKR_OK) { 298 fprintf(stderr, 299 "C_SignUpdate: Error = 0x%.8lX\n", 300 rv); 301 error = 1; 302 goto exit_sign; 303 } 304 } 305 306 len = 16; 307 rv = pkcs_C_SignFinal(hSession, (CK_BYTE_PTR) digest, &len); 308 if (rv != CKR_OK) { 309 fprintf(stderr, "C_SignFinal: Error = 0x%.8lX\n", rv); 310 error = 1; 311 goto exit_sign; 312 } 313 if (len != 16) { 314 fprintf(stderr, "C_SignFinal: bad length = %lu\n", len); 315 error = 1; 316 } 317 318 for (i = 0; i < 16; i++) 319 printf("%02x", digest[i] & 0xff); 320 printf("\n"); 321 322 exit_sign: 323 rv = pkcs_C_DestroyObject(hSession, hKey); 324 if ((error == 0) && (rv != CKR_OK)) { 325 fprintf(stderr, "C_DestroyObject: Error = 0x%.8lX\n", rv); 326 error = 1; 327 } 328 329 exit_session: 330 pk11_return_session(&pctx); 331 (void) pk11_finalize(); 332 333 exit(error); 334 } 335