1/* 2 * Copyright (c) 2019 Markus Friedl 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include <stdint.h> 18#include <stdlib.h> 19#include <string.h> 20#include <stdio.h> 21#include <stddef.h> 22#include <stdarg.h> 23#include <sha2.h> 24 25#include "crypto_api.h" 26#include "sk-api.h" 27 28#include <openssl/opensslv.h> 29#include <openssl/crypto.h> 30#include <openssl/evp.h> 31#include <openssl/bn.h> 32#include <openssl/ec.h> 33#include <openssl/ecdsa.h> 34#include <openssl/pem.h> 35 36/* #define SK_DEBUG 1 */ 37 38#if SSH_SK_VERSION_MAJOR != 0x000a0000 39# error SK API has changed, sk-dummy.c needs an update 40#endif 41 42#ifdef SK_DUMMY_INTEGRATE 43# define sk_api_version ssh_sk_api_version 44# define sk_enroll ssh_sk_enroll 45# define sk_sign ssh_sk_sign 46# define sk_load_resident_keys ssh_sk_load_resident_keys 47#endif /* !SK_STANDALONE */ 48 49static void skdebug(const char *func, const char *fmt, ...) 50 __attribute__((__format__ (printf, 2, 3))); 51 52static void 53skdebug(const char *func, const char *fmt, ...) 54{ 55#if defined(SK_DEBUG) 56 va_list ap; 57 58 va_start(ap, fmt); 59 fprintf(stderr, "sk-dummy %s: ", func); 60 vfprintf(stderr, fmt, ap); 61 fputc('\n', stderr); 62 va_end(ap); 63#else 64 (void)func; /* XXX */ 65 (void)fmt; /* XXX */ 66#endif 67} 68 69uint32_t 70sk_api_version(void) 71{ 72 return SSH_SK_VERSION_MAJOR; 73} 74 75static int 76pack_key_ecdsa(struct sk_enroll_response *response) 77{ 78 EC_KEY *key = NULL; 79 const EC_GROUP *g; 80 const EC_POINT *q; 81 int ret = -1; 82 long privlen; 83 BIO *bio = NULL; 84 char *privptr; 85 86 response->public_key = NULL; 87 response->public_key_len = 0; 88 response->key_handle = NULL; 89 response->key_handle_len = 0; 90 91 if ((key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) { 92 skdebug(__func__, "EC_KEY_new_by_curve_name"); 93 goto out; 94 } 95 if (EC_KEY_generate_key(key) != 1) { 96 skdebug(__func__, "EC_KEY_generate_key"); 97 goto out; 98 } 99 EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE); 100 if ((bio = BIO_new(BIO_s_mem())) == NULL || 101 (g = EC_KEY_get0_group(key)) == NULL || 102 (q = EC_KEY_get0_public_key(key)) == NULL) { 103 skdebug(__func__, "couldn't get key parameters"); 104 goto out; 105 } 106 response->public_key_len = EC_POINT_point2oct(g, q, 107 POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); 108 if (response->public_key_len == 0 || response->public_key_len > 2048) { 109 skdebug(__func__, "bad pubkey length %zu", 110 response->public_key_len); 111 goto out; 112 } 113 if ((response->public_key = malloc(response->public_key_len)) == NULL) { 114 skdebug(__func__, "malloc pubkey failed"); 115 goto out; 116 } 117 if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED, 118 response->public_key, response->public_key_len, NULL) == 0) { 119 skdebug(__func__, "EC_POINT_point2oct failed"); 120 goto out; 121 } 122 /* Key handle contains PEM encoded private key */ 123 if (!PEM_write_bio_ECPrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) { 124 skdebug(__func__, "PEM_write_bio_ECPrivateKey failed"); 125 goto out; 126 } 127 if ((privlen = BIO_get_mem_data(bio, &privptr)) <= 0) { 128 skdebug(__func__, "BIO_get_mem_data failed"); 129 goto out; 130 } 131 if ((response->key_handle = malloc(privlen)) == NULL) { 132 skdebug(__func__, "malloc key_handle failed"); 133 goto out; 134 } 135 response->key_handle_len = (size_t)privlen; 136 memcpy(response->key_handle, privptr, response->key_handle_len); 137 /* success */ 138 ret = 0; 139 out: 140 if (ret != 0) { 141 if (response->public_key != NULL) { 142 memset(response->public_key, 0, 143 response->public_key_len); 144 free(response->public_key); 145 response->public_key = NULL; 146 } 147 if (response->key_handle != NULL) { 148 memset(response->key_handle, 0, 149 response->key_handle_len); 150 free(response->key_handle); 151 response->key_handle = NULL; 152 } 153 } 154 BIO_free(bio); 155 EC_KEY_free(key); 156 return ret; 157} 158 159static int 160pack_key_ed25519(struct sk_enroll_response *response) 161{ 162 int ret = -1; 163 u_char pk[crypto_sign_ed25519_PUBLICKEYBYTES]; 164 u_char sk[crypto_sign_ed25519_SECRETKEYBYTES]; 165 166 response->public_key = NULL; 167 response->public_key_len = 0; 168 response->key_handle = NULL; 169 response->key_handle_len = 0; 170 171 memset(pk, 0, sizeof(pk)); 172 memset(sk, 0, sizeof(sk)); 173 crypto_sign_ed25519_keypair(pk, sk); 174 175 response->public_key_len = sizeof(pk); 176 if ((response->public_key = malloc(response->public_key_len)) == NULL) { 177 skdebug(__func__, "malloc pubkey failed"); 178 goto out; 179 } 180 memcpy(response->public_key, pk, sizeof(pk)); 181 /* Key handle contains sk */ 182 response->key_handle_len = sizeof(sk); 183 if ((response->key_handle = malloc(response->key_handle_len)) == NULL) { 184 skdebug(__func__, "malloc key_handle failed"); 185 goto out; 186 } 187 memcpy(response->key_handle, sk, sizeof(sk)); 188 /* success */ 189 ret = 0; 190 out: 191 if (ret != 0) 192 free(response->public_key); 193 return ret; 194} 195 196static int 197check_options(struct sk_option **options) 198{ 199 size_t i; 200 201 if (options == NULL) 202 return 0; 203 for (i = 0; options[i] != NULL; i++) { 204 skdebug(__func__, "requested unsupported option %s", 205 options[i]->name); 206 if (options[i]->required) { 207 skdebug(__func__, "unknown required option"); 208 return -1; 209 } 210 } 211 return 0; 212} 213 214int 215sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, 216 const char *application, uint8_t flags, const char *pin, 217 struct sk_option **options, struct sk_enroll_response **enroll_response) 218{ 219 struct sk_enroll_response *response = NULL; 220 int ret = SSH_SK_ERR_GENERAL; 221 222 (void)flags; /* XXX; unused */ 223 224 if (enroll_response == NULL) { 225 skdebug(__func__, "enroll_response == NULL"); 226 goto out; 227 } 228 *enroll_response = NULL; 229 if (check_options(options) != 0) 230 goto out; /* error already logged */ 231 if ((response = calloc(1, sizeof(*response))) == NULL) { 232 skdebug(__func__, "calloc response failed"); 233 goto out; 234 } 235 response->flags = flags; 236 switch(alg) { 237 case SSH_SK_ECDSA: 238 if (pack_key_ecdsa(response) != 0) 239 goto out; 240 break; 241 case SSH_SK_ED25519: 242 if (pack_key_ed25519(response) != 0) 243 goto out; 244 break; 245 default: 246 skdebug(__func__, "unsupported key type %d", alg); 247 return -1; 248 } 249 /* Have to return something here */ 250 if ((response->signature = calloc(1, 1)) == NULL) { 251 skdebug(__func__, "calloc signature failed"); 252 goto out; 253 } 254 response->signature_len = 0; 255 256 *enroll_response = response; 257 response = NULL; 258 ret = 0; 259 out: 260 if (response != NULL) { 261 free(response->public_key); 262 free(response->key_handle); 263 free(response->signature); 264 free(response->attestation_cert); 265 free(response); 266 } 267 return ret; 268} 269 270static void 271dump(const char *preamble, const void *sv, size_t l) 272{ 273#ifdef SK_DEBUG 274 const u_char *s = (const u_char *)sv; 275 size_t i; 276 277 fprintf(stderr, "%s (len %zu):\n", preamble, l); 278 for (i = 0; i < l; i++) { 279 if (i % 16 == 0) 280 fprintf(stderr, "%04zu: ", i); 281 fprintf(stderr, "%02x", s[i]); 282 if (i % 16 == 15 || i == l - 1) 283 fprintf(stderr, "\n"); 284 } 285#endif 286} 287 288static int 289sig_ecdsa(const uint8_t *message, size_t message_len, 290 const char *application, uint32_t counter, uint8_t flags, 291 const uint8_t *key_handle, size_t key_handle_len, 292 struct sk_sign_response *response) 293{ 294 ECDSA_SIG *sig = NULL; 295 const BIGNUM *sig_r, *sig_s; 296 int ret = -1; 297 BIO *bio = NULL; 298 EVP_PKEY *pk = NULL; 299 EC_KEY *ec = NULL; 300 SHA2_CTX ctx; 301 uint8_t apphash[SHA256_DIGEST_LENGTH]; 302 uint8_t sighash[SHA256_DIGEST_LENGTH]; 303 uint8_t countbuf[4]; 304 305 /* Decode EC_KEY from key handle */ 306 if ((bio = BIO_new(BIO_s_mem())) == NULL || 307 BIO_write(bio, key_handle, key_handle_len) != (int)key_handle_len) { 308 skdebug(__func__, "BIO setup failed"); 309 goto out; 310 } 311 if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, "")) == NULL) { 312 skdebug(__func__, "PEM_read_bio_PrivateKey failed"); 313 goto out; 314 } 315 if (EVP_PKEY_base_id(pk) != EVP_PKEY_EC) { 316 skdebug(__func__, "Not an EC key: %d", EVP_PKEY_base_id(pk)); 317 goto out; 318 } 319 if ((ec = EVP_PKEY_get1_EC_KEY(pk)) == NULL) { 320 skdebug(__func__, "EVP_PKEY_get1_EC_KEY failed"); 321 goto out; 322 } 323 /* Expect message to be pre-hashed */ 324 if (message_len != SHA256_DIGEST_LENGTH) { 325 skdebug(__func__, "bad message len %zu", message_len); 326 goto out; 327 } 328 /* Prepare data to be signed */ 329 dump("message", message, message_len); 330 SHA256Init(&ctx); 331 SHA256Update(&ctx, (const u_char *)application, strlen(application)); 332 SHA256Final(apphash, &ctx); 333 dump("apphash", apphash, sizeof(apphash)); 334 countbuf[0] = (counter >> 24) & 0xff; 335 countbuf[1] = (counter >> 16) & 0xff; 336 countbuf[2] = (counter >> 8) & 0xff; 337 countbuf[3] = counter & 0xff; 338 dump("countbuf", countbuf, sizeof(countbuf)); 339 dump("flags", &flags, sizeof(flags)); 340 SHA256Init(&ctx); 341 SHA256Update(&ctx, apphash, sizeof(apphash)); 342 SHA256Update(&ctx, &flags, sizeof(flags)); 343 SHA256Update(&ctx, countbuf, sizeof(countbuf)); 344 SHA256Update(&ctx, message, message_len); 345 SHA256Final(sighash, &ctx); 346 dump("sighash", sighash, sizeof(sighash)); 347 /* create and encode signature */ 348 if ((sig = ECDSA_do_sign(sighash, sizeof(sighash), ec)) == NULL) { 349 skdebug(__func__, "ECDSA_do_sign failed"); 350 goto out; 351 } 352 ECDSA_SIG_get0(sig, &sig_r, &sig_s); 353 response->sig_r_len = BN_num_bytes(sig_r); 354 response->sig_s_len = BN_num_bytes(sig_s); 355 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL || 356 (response->sig_s = calloc(1, response->sig_s_len)) == NULL) { 357 skdebug(__func__, "calloc signature failed"); 358 goto out; 359 } 360 BN_bn2bin(sig_r, response->sig_r); 361 BN_bn2bin(sig_s, response->sig_s); 362 ret = 0; 363 out: 364 explicit_bzero(&ctx, sizeof(ctx)); 365 explicit_bzero(&apphash, sizeof(apphash)); 366 explicit_bzero(&sighash, sizeof(sighash)); 367 ECDSA_SIG_free(sig); 368 if (ret != 0) { 369 free(response->sig_r); 370 free(response->sig_s); 371 response->sig_r = NULL; 372 response->sig_s = NULL; 373 } 374 BIO_free(bio); 375 EC_KEY_free(ec); 376 EVP_PKEY_free(pk); 377 return ret; 378} 379 380static int 381sig_ed25519(const uint8_t *message, size_t message_len, 382 const char *application, uint32_t counter, uint8_t flags, 383 const uint8_t *key_handle, size_t key_handle_len, 384 struct sk_sign_response *response) 385{ 386 size_t o; 387 int ret = -1; 388 SHA2_CTX ctx; 389 uint8_t apphash[SHA256_DIGEST_LENGTH]; 390 uint8_t signbuf[sizeof(apphash) + sizeof(flags) + 391 sizeof(counter) + SHA256_DIGEST_LENGTH]; 392 uint8_t sig[crypto_sign_ed25519_BYTES + sizeof(signbuf)]; 393 unsigned long long smlen; 394 395 if (key_handle_len != crypto_sign_ed25519_SECRETKEYBYTES) { 396 skdebug(__func__, "bad key handle length %zu", key_handle_len); 397 goto out; 398 } 399 /* Expect message to be pre-hashed */ 400 if (message_len != SHA256_DIGEST_LENGTH) { 401 skdebug(__func__, "bad message len %zu", message_len); 402 goto out; 403 } 404 /* Prepare data to be signed */ 405 dump("message", message, message_len); 406 SHA256Init(&ctx); 407 SHA256Update(&ctx, (const u_char *)application, strlen(application)); 408 SHA256Final(apphash, &ctx); 409 dump("apphash", apphash, sizeof(apphash)); 410 411 memcpy(signbuf, apphash, sizeof(apphash)); 412 o = sizeof(apphash); 413 signbuf[o++] = flags; 414 signbuf[o++] = (counter >> 24) & 0xff; 415 signbuf[o++] = (counter >> 16) & 0xff; 416 signbuf[o++] = (counter >> 8) & 0xff; 417 signbuf[o++] = counter & 0xff; 418 memcpy(signbuf + o, message, message_len); 419 o += message_len; 420 if (o != sizeof(signbuf)) { 421 skdebug(__func__, "bad sign buf len %zu, expected %zu", 422 o, sizeof(signbuf)); 423 goto out; 424 } 425 dump("signbuf", signbuf, sizeof(signbuf)); 426 /* create and encode signature */ 427 smlen = sizeof(signbuf); 428 if (crypto_sign_ed25519(sig, &smlen, signbuf, sizeof(signbuf), 429 key_handle) != 0) { 430 skdebug(__func__, "crypto_sign_ed25519 failed"); 431 goto out; 432 } 433 if (smlen <= sizeof(signbuf)) { 434 skdebug(__func__, "bad sign smlen %llu, expected min %zu", 435 smlen, sizeof(signbuf) + 1); 436 goto out; 437 } 438 response->sig_r_len = (size_t)(smlen - sizeof(signbuf)); 439 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) { 440 skdebug(__func__, "calloc signature failed"); 441 goto out; 442 } 443 memcpy(response->sig_r, sig, response->sig_r_len); 444 dump("sig_r", response->sig_r, response->sig_r_len); 445 ret = 0; 446 out: 447 explicit_bzero(&ctx, sizeof(ctx)); 448 explicit_bzero(&apphash, sizeof(apphash)); 449 explicit_bzero(&signbuf, sizeof(signbuf)); 450 explicit_bzero(&sig, sizeof(sig)); 451 if (ret != 0) { 452 free(response->sig_r); 453 response->sig_r = NULL; 454 } 455 return ret; 456} 457 458int 459sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, 460 const char *application, const uint8_t *key_handle, size_t key_handle_len, 461 uint8_t flags, const char *pin, struct sk_option **options, 462 struct sk_sign_response **sign_response) 463{ 464 struct sk_sign_response *response = NULL; 465 int ret = SSH_SK_ERR_GENERAL; 466 SHA2_CTX ctx; 467 uint8_t message[32]; 468 469 if (sign_response == NULL) { 470 skdebug(__func__, "sign_response == NULL"); 471 goto out; 472 } 473 *sign_response = NULL; 474 if (check_options(options) != 0) 475 goto out; /* error already logged */ 476 if ((response = calloc(1, sizeof(*response))) == NULL) { 477 skdebug(__func__, "calloc response failed"); 478 goto out; 479 } 480 SHA256Init(&ctx); 481 SHA256Update(&ctx, data, datalen); 482 SHA256Final(message, &ctx); 483 response->flags = flags; 484 response->counter = 0x12345678; 485 switch(alg) { 486 case SSH_SK_ECDSA: 487 if (sig_ecdsa(message, sizeof(message), application, 488 response->counter, flags, key_handle, key_handle_len, 489 response) != 0) 490 goto out; 491 break; 492 case SSH_SK_ED25519: 493 if (sig_ed25519(message, sizeof(message), application, 494 response->counter, flags, key_handle, key_handle_len, 495 response) != 0) 496 goto out; 497 break; 498 default: 499 skdebug(__func__, "unsupported key type %d", alg); 500 return -1; 501 } 502 *sign_response = response; 503 response = NULL; 504 ret = 0; 505 out: 506 explicit_bzero(message, sizeof(message)); 507 if (response != NULL) { 508 free(response->sig_r); 509 free(response->sig_s); 510 free(response); 511 } 512 return ret; 513} 514 515int 516sk_load_resident_keys(const char *pin, struct sk_option **options, 517 struct sk_resident_key ***rks, size_t *nrks) 518{ 519 return SSH_SK_ERR_UNSUPPORTED; 520} 521