diff options
Diffstat (limited to 'src/lib/libcrypto')
| -rw-r--r-- | src/lib/libcrypto/engine/hw_cryptodev.c | 168 |
1 files changed, 85 insertions, 83 deletions
diff --git a/src/lib/libcrypto/engine/hw_cryptodev.c b/src/lib/libcrypto/engine/hw_cryptodev.c index d58c25ae9a..84b245e49f 100644 --- a/src/lib/libcrypto/engine/hw_cryptodev.c +++ b/src/lib/libcrypto/engine/hw_cryptodev.c | |||
| @@ -45,8 +45,11 @@ | |||
| 45 | #include <errno.h> | 45 | #include <errno.h> |
| 46 | #include <string.h> | 46 | #include <string.h> |
| 47 | 47 | ||
| 48 | static int cryptodev_fd = -1; | 48 | struct dev_crypto_state { |
| 49 | static int cryptodev_sessions = 0; | 49 | struct session_op d_sess; |
| 50 | int d_fd; | ||
| 51 | }; | ||
| 52 | |||
| 50 | static u_int32_t cryptodev_asymfeat = 0; | 53 | static u_int32_t cryptodev_asymfeat = 0; |
| 51 | 54 | ||
| 52 | static int bn2crparam(const BIGNUM *a, struct crparam *crp); | 55 | static int bn2crparam(const BIGNUM *a, struct crparam *crp); |
| @@ -106,31 +109,38 @@ static struct { | |||
| 106 | }; | 109 | }; |
| 107 | 110 | ||
| 108 | /* | 111 | /* |
| 109 | * Return 1 if /dev/crypto seems usable, 0 otherwise , also | 112 | * Return a fd if /dev/crypto seems usable, 0 otherwise. |
| 110 | * does most of the work of initting the device, if not already | ||
| 111 | * done.. This should leave is with global fd initialized with CRIOGET. | ||
| 112 | */ | 113 | */ |
| 113 | static int | 114 | static int |
| 114 | check_dev_crypto() | 115 | get_dev_crypto() |
| 115 | { | 116 | { |
| 116 | int fd; | 117 | int fd, retfd; |
| 117 | 118 | ||
| 118 | if (cryptodev_fd == -1) { | 119 | if ((fd = open("/dev/crypto", O_RDWR, 0)) == -1) |
| 119 | if ((fd = open("/dev/crypto", O_RDWR, 0)) == -1) | 120 | return (-1); |
| 120 | return (0); | 121 | if (ioctl(fd, CRIOGET, &retfd) == -1) { |
| 121 | if (ioctl(fd, CRIOGET, &cryptodev_fd) == -1) { | ||
| 122 | close(fd); | ||
| 123 | return (0); | ||
| 124 | } | ||
| 125 | close(fd); | 122 | close(fd); |
| 126 | /* close on exec */ | 123 | return (-1); |
| 127 | if (fcntl(cryptodev_fd, F_SETFD, 1) == -1) { | ||
| 128 | close(cryptodev_fd); | ||
| 129 | cryptodev_fd = -1; | ||
| 130 | return (0); | ||
| 131 | } | ||
| 132 | } | 124 | } |
| 133 | return (1); | 125 | close(fd); |
| 126 | |||
| 127 | /* close on exec */ | ||
| 128 | if (fcntl(retfd, F_SETFD, 1) == -1) { | ||
| 129 | close(retfd); | ||
| 130 | return (-1); | ||
| 131 | } | ||
| 132 | return (retfd); | ||
| 133 | } | ||
| 134 | |||
| 135 | /* Caching version for asym operations */ | ||
| 136 | static int | ||
| 137 | get_asym_dev_crypto() | ||
| 138 | { | ||
| 139 | static int fd = -1; | ||
| 140 | |||
| 141 | if (fd == -1) | ||
| 142 | fd = get_dev_crypto(); | ||
| 143 | return fd; | ||
| 134 | } | 144 | } |
| 135 | 145 | ||
| 136 | /* | 146 | /* |
| @@ -188,8 +198,12 @@ get_cryptodev_ciphers(const int **cnids) | |||
| 188 | { | 198 | { |
| 189 | static int nids[CRYPTO_ALGORITHM_MAX]; | 199 | static int nids[CRYPTO_ALGORITHM_MAX]; |
| 190 | struct session_op sess; | 200 | struct session_op sess; |
| 191 | int i, count = 0; | 201 | int fd, i, count = 0; |
| 192 | 202 | ||
| 203 | if ((fd = get_dev_crypto()) < 0) { | ||
| 204 | *nids = NULL; | ||
| 205 | return (0); | ||
| 206 | } | ||
| 193 | memset(&sess, 0, sizeof(sess)); | 207 | memset(&sess, 0, sizeof(sess)); |
| 194 | sess.key = (caddr_t)"123456781234567812345678"; | 208 | sess.key = (caddr_t)"123456781234567812345678"; |
| 195 | 209 | ||
| @@ -199,10 +213,12 @@ get_cryptodev_ciphers(const int **cnids) | |||
| 199 | sess.cipher = ciphers[i].id; | 213 | sess.cipher = ciphers[i].id; |
| 200 | sess.keylen = ciphers[i].keylen; | 214 | sess.keylen = ciphers[i].keylen; |
| 201 | sess.mac = 0; | 215 | sess.mac = 0; |
| 202 | if (ioctl(cryptodev_fd, CIOCGSESSION, &sess) != -1 && | 216 | if (ioctl(fd, CIOCGSESSION, &sess) != -1 && |
| 203 | ioctl(cryptodev_fd, CIOCFSESSION, &sess.ses) != -1) | 217 | ioctl(fd, CIOCFSESSION, &sess.ses) != -1) |
| 204 | nids[count++] = ciphers[i].nid; | 218 | nids[count++] = ciphers[i].nid; |
| 205 | } | 219 | } |
| 220 | close(fd); | ||
| 221 | |||
| 206 | if (count > 0) | 222 | if (count > 0) |
| 207 | *cnids = nids; | 223 | *cnids = nids; |
| 208 | else | 224 | else |
| @@ -221,18 +237,24 @@ get_cryptodev_digests(const int **cnids) | |||
| 221 | { | 237 | { |
| 222 | static int nids[CRYPTO_ALGORITHM_MAX]; | 238 | static int nids[CRYPTO_ALGORITHM_MAX]; |
| 223 | struct session_op sess; | 239 | struct session_op sess; |
| 224 | int i, count = 0; | 240 | int fd, i, count = 0; |
| 225 | 241 | ||
| 242 | if ((fd = get_dev_crypto()) < 0) { | ||
| 243 | *nids = NULL; | ||
| 244 | return (0); | ||
| 245 | } | ||
| 226 | memset(&sess, 0, sizeof(sess)); | 246 | memset(&sess, 0, sizeof(sess)); |
| 227 | for (i = 0; digests[i].id && count < CRYPTO_ALGORITHM_MAX; i++) { | 247 | for (i = 0; digests[i].id && count < CRYPTO_ALGORITHM_MAX; i++) { |
| 228 | if (digests[i].nid == NID_undef) | 248 | if (digests[i].nid == NID_undef) |
| 229 | continue; | 249 | continue; |
| 230 | sess.mac = digests[i].id; | 250 | sess.mac = digests[i].id; |
| 231 | sess.cipher = 0; | 251 | sess.cipher = 0; |
| 232 | if (ioctl(cryptodev_fd, CIOCGSESSION, &sess) != -1 && | 252 | if (ioctl(fd, CIOCGSESSION, &sess) != -1 && |
| 233 | ioctl(cryptodev_fd, CIOCFSESSION, &sess.ses) != -1) | 253 | ioctl(fd, CIOCFSESSION, &sess.ses) != -1) |
| 234 | nids[count++] = digests[i].nid; | 254 | nids[count++] = digests[i].nid; |
| 235 | } | 255 | } |
| 256 | close(fd); | ||
| 257 | |||
| 236 | if (count > 0) | 258 | if (count > 0) |
| 237 | *cnids = nids; | 259 | *cnids = nids; |
| 238 | else | 260 | else |
| @@ -264,31 +286,12 @@ get_cryptodev_digests(const int **cnids) | |||
| 264 | int | 286 | int |
| 265 | cryptodev_usable_ciphers(const int **nids) | 287 | cryptodev_usable_ciphers(const int **nids) |
| 266 | { | 288 | { |
| 267 | struct syslog_data sd = SYSLOG_DATA_INIT; | ||
| 268 | |||
| 269 | if (!check_dev_crypto()) { | ||
| 270 | *nids = NULL; | ||
| 271 | return (0); | ||
| 272 | } | ||
| 273 | |||
| 274 | /* find what the device can do. Unfortunately, we don't | ||
| 275 | * necessarily want all of these yet, because we aren't | ||
| 276 | * yet set up to do them | ||
| 277 | */ | ||
| 278 | return (get_cryptodev_ciphers(nids)); | 289 | return (get_cryptodev_ciphers(nids)); |
| 279 | |||
| 280 | /* | ||
| 281 | * find out what asymmetric crypto algorithms we support | ||
| 282 | */ | ||
| 283 | if (ioctl(cryptodev_fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) { | ||
| 284 | syslog_r(LOG_ERR, &sd, "CIOCASYMFEAT failed (%m)"); | ||
| 285 | } | ||
| 286 | } | 290 | } |
| 287 | 291 | ||
| 288 | int | 292 | int |
| 289 | cryptodev_usable_digests(const int **nids) | 293 | cryptodev_usable_digests(const int **nids) |
| 290 | { | 294 | { |
| 291 | #if 1 | ||
| 292 | /* | 295 | /* |
| 293 | * XXXX just disable all digests for now, because it sucks. | 296 | * XXXX just disable all digests for now, because it sucks. |
| 294 | * we need a better way to decide this - i.e. I may not | 297 | * we need a better way to decide this - i.e. I may not |
| @@ -303,29 +306,20 @@ cryptodev_usable_digests(const int **nids) | |||
| 303 | */ | 306 | */ |
| 304 | *nids = NULL; | 307 | *nids = NULL; |
| 305 | return (0); | 308 | return (0); |
| 306 | #endif | ||
| 307 | |||
| 308 | if (!check_dev_crypto()) { | ||
| 309 | *nids = NULL; | ||
| 310 | return (0); | ||
| 311 | } | ||
| 312 | return (get_cryptodev_digests(nids)); | ||
| 313 | } | 309 | } |
| 314 | 310 | ||
| 315 | |||
| 316 | int | 311 | int |
| 317 | cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, | 312 | cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, |
| 318 | const unsigned char *in, unsigned int inl) | 313 | const unsigned char *in, unsigned int inl) |
| 319 | { | 314 | { |
| 320 | struct crypt_op cryp; | 315 | struct crypt_op cryp; |
| 321 | struct session_op *sess = ctx->cipher_data; | 316 | struct dev_crypto_state *state = ctx->cipher_data; |
| 317 | struct session_op *sess = &state->d_sess; | ||
| 322 | void *iiv; | 318 | void *iiv; |
| 323 | unsigned char save_iv[EVP_MAX_IV_LENGTH]; | 319 | unsigned char save_iv[EVP_MAX_IV_LENGTH]; |
| 324 | struct syslog_data sd = SYSLOG_DATA_INIT; | 320 | struct syslog_data sd = SYSLOG_DATA_INIT; |
| 325 | 321 | ||
| 326 | if (cryptodev_fd == -1) | 322 | if (state->d_fd < 0) |
| 327 | return (0); | ||
| 328 | if (sess == NULL) | ||
| 329 | return (0); | 323 | return (0); |
| 330 | if (!inl) | 324 | if (!inl) |
| 331 | return (1); | 325 | return (1); |
| @@ -352,7 +346,7 @@ cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, | |||
| 352 | } else | 346 | } else |
| 353 | cryp.iv = NULL; | 347 | cryp.iv = NULL; |
| 354 | 348 | ||
| 355 | if (ioctl(cryptodev_fd, CIOCCRYPT, &cryp) == -1) { | 349 | if (ioctl(state->d_fd, CIOCCRYPT, &cryp) == -1) { |
| 356 | /* XXX need better errror handling | 350 | /* XXX need better errror handling |
| 357 | * this can fail for a number of different reasons. | 351 | * this can fail for a number of different reasons. |
| 358 | */ | 352 | */ |
| @@ -374,16 +368,14 @@ int | |||
| 374 | cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, | 368 | cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, |
| 375 | const unsigned char *iv, int enc) | 369 | const unsigned char *iv, int enc) |
| 376 | { | 370 | { |
| 377 | struct session_op *sess = ctx->cipher_data; | 371 | struct dev_crypto_state *state = ctx->cipher_data; |
| 372 | struct session_op *sess = &state->d_sess; | ||
| 378 | struct syslog_data sd = SYSLOG_DATA_INIT; | 373 | struct syslog_data sd = SYSLOG_DATA_INIT; |
| 379 | int cipher; | 374 | int cipher; |
| 380 | 375 | ||
| 381 | if ((cipher = cipher_nid_to_cryptodev(ctx->cipher->nid)) == NID_undef) | 376 | if ((cipher = cipher_nid_to_cryptodev(ctx->cipher->nid)) == NID_undef) |
| 382 | return (0); | 377 | return (0); |
| 383 | 378 | ||
| 384 | if (!check_dev_crypto()) | ||
| 385 | return (0); | ||
| 386 | |||
| 387 | if (ctx->cipher->iv_len > cryptodev_max_iv(cipher)) | 379 | if (ctx->cipher->iv_len > cryptodev_max_iv(cipher)) |
| 388 | return (0); | 380 | return (0); |
| 389 | 381 | ||
| @@ -392,15 +384,20 @@ cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, | |||
| 392 | 384 | ||
| 393 | memset(sess, 0, sizeof(struct session_op)); | 385 | memset(sess, 0, sizeof(struct session_op)); |
| 394 | 386 | ||
| 387 | if ((state->d_fd = get_dev_crypto()) < 0) | ||
| 388 | return (0); | ||
| 389 | |||
| 395 | sess->key = (unsigned char *)key; | 390 | sess->key = (unsigned char *)key; |
| 396 | sess->keylen = ctx->key_len; | 391 | sess->keylen = ctx->key_len; |
| 397 | sess->cipher = cipher; | 392 | sess->cipher = cipher; |
| 398 | 393 | ||
| 399 | if (ioctl(cryptodev_fd, CIOCGSESSION, sess) == -1) { | 394 | if (ioctl(state->d_fd, CIOCGSESSION, sess) == -1) { |
| 400 | syslog_r(LOG_ERR, &sd, "CIOCGSESSION failed (%m)"); | 395 | syslog_r(LOG_ERR, &sd, "CIOCGSESSION failed (%m)"); |
| 396 | |||
| 397 | close(state->d_fd); | ||
| 398 | state->d_fd = -1; | ||
| 401 | return (0); | 399 | return (0); |
| 402 | } | 400 | } |
| 403 | cryptodev_sessions++; | ||
| 404 | return (1); | 401 | return (1); |
| 405 | } | 402 | } |
| 406 | 403 | ||
| @@ -412,10 +409,11 @@ int | |||
| 412 | cryptodev_cleanup(EVP_CIPHER_CTX *ctx) | 409 | cryptodev_cleanup(EVP_CIPHER_CTX *ctx) |
| 413 | { | 410 | { |
| 414 | int ret = 0; | 411 | int ret = 0; |
| 415 | struct session_op *sess = ctx->cipher_data; | 412 | struct dev_crypto_state *state = ctx->cipher_data; |
| 413 | struct session_op *sess = &state->d_sess; | ||
| 416 | struct syslog_data sd = SYSLOG_DATA_INIT; | 414 | struct syslog_data sd = SYSLOG_DATA_INIT; |
| 417 | 415 | ||
| 418 | if (sess == NULL) | 416 | if (state->d_fd < 0) |
| 419 | return (0); | 417 | return (0); |
| 420 | 418 | ||
| 421 | /* XXX if this ioctl fails, someting's wrong. the invoker | 419 | /* XXX if this ioctl fails, someting's wrong. the invoker |
| @@ -429,17 +427,15 @@ cryptodev_cleanup(EVP_CIPHER_CTX *ctx) | |||
| 429 | * print messages to users of the library. hmm.. | 427 | * print messages to users of the library. hmm.. |
| 430 | */ | 428 | */ |
| 431 | 429 | ||
| 432 | if (ioctl(cryptodev_fd, CIOCFSESSION, &sess->ses) == -1) { | 430 | if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) == -1) { |
| 433 | syslog_r(LOG_ERR, &sd, "CIOCFSESSION failed (%m)"); | 431 | syslog_r(LOG_ERR, &sd, "CIOCFSESSION failed (%m)"); |
| 434 | ret = 0; | 432 | ret = 0; |
| 435 | } else { | 433 | } else { |
| 436 | cryptodev_sessions--; | ||
| 437 | ret = 1; | 434 | ret = 1; |
| 438 | } | 435 | } |
| 439 | if (cryptodev_sessions == 0 && cryptodev_fd != -1 ) { | 436 | close(state->d_fd); |
| 440 | close(cryptodev_fd); /* XXX should this be closed? */ | 437 | state->d_fd = -1; |
| 441 | cryptodev_fd = -1; | 438 | |
| 442 | } | ||
| 443 | return (ret); | 439 | return (ret); |
| 444 | } | 440 | } |
| 445 | 441 | ||
| @@ -662,7 +658,10 @@ zapparams(struct crypt_kop *kop) | |||
| 662 | static int | 658 | static int |
| 663 | cryptodev_sym(struct crypt_kop *kop, int rlen, BIGNUM *r, int slen, BIGNUM *s) | 659 | cryptodev_sym(struct crypt_kop *kop, int rlen, BIGNUM *r, int slen, BIGNUM *s) |
| 664 | { | 660 | { |
| 665 | int ret = -1; | 661 | int fd, ret = -1; |
| 662 | |||
| 663 | if ((fd = get_asym_dev_crypto()) < 0) | ||
| 664 | return (ret); | ||
| 666 | 665 | ||
| 667 | if (r) { | 666 | if (r) { |
| 668 | kop->crk_param[kop->crk_iparams].crp_p = calloc(rlen, sizeof(char)); | 667 | kop->crk_param[kop->crk_iparams].crp_p = calloc(rlen, sizeof(char)); |
| @@ -675,13 +674,14 @@ cryptodev_sym(struct crypt_kop *kop, int rlen, BIGNUM *r, int slen, BIGNUM *s) | |||
| 675 | kop->crk_oparams++; | 674 | kop->crk_oparams++; |
| 676 | } | 675 | } |
| 677 | 676 | ||
| 678 | if (ioctl(cryptodev_fd, CIOCKEY, kop) == 0) { | 677 | if (ioctl(fd, CIOCKEY, kop) == 0) { |
| 679 | if (r) | 678 | if (r) |
| 680 | crparam2bn(&kop->crk_param[kop->crk_iparams], r); | 679 | crparam2bn(&kop->crk_param[kop->crk_iparams], r); |
| 681 | if (s) | 680 | if (s) |
| 682 | crparam2bn(&kop->crk_param[kop->crk_iparams+1], s); | 681 | crparam2bn(&kop->crk_param[kop->crk_iparams+1], s); |
| 683 | ret = 0; | 682 | ret = 0; |
| 684 | } | 683 | } |
| 684 | |||
| 685 | return (ret); | 685 | return (ret); |
| 686 | } | 686 | } |
| 687 | 687 | ||
| @@ -940,7 +940,10 @@ cryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) | |||
| 940 | { | 940 | { |
| 941 | struct crypt_kop kop; | 941 | struct crypt_kop kop; |
| 942 | int dhret = 1; | 942 | int dhret = 1; |
| 943 | int keylen; | 943 | int fd, keylen; |
| 944 | |||
| 945 | if ((fd = get_asym_dev_crypto()) < 0) | ||
| 946 | return (-1); | ||
| 944 | 947 | ||
| 945 | keylen = BN_num_bits(dh->p); | 948 | keylen = BN_num_bits(dh->p); |
| 946 | 949 | ||
| @@ -960,7 +963,7 @@ cryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) | |||
| 960 | kop.crk_param[3].crp_nbits = keylen * 8; | 963 | kop.crk_param[3].crp_nbits = keylen * 8; |
| 961 | kop.crk_oparams = 1; | 964 | kop.crk_oparams = 1; |
| 962 | 965 | ||
| 963 | if (ioctl(cryptodev_fd, CIOCKEY, &kop) == -1) { | 966 | if (ioctl(fd, CIOCKEY, &kop) == -1) { |
| 964 | const DH_METHOD *meth = DH_OpenSSL(); | 967 | const DH_METHOD *meth = DH_OpenSSL(); |
| 965 | 968 | ||
| 966 | dhret = (meth->compute_key)(key, pub_key, dh); | 969 | dhret = (meth->compute_key)(key, pub_key, dh); |
| @@ -1005,22 +1008,22 @@ ENGINE_load_cryptodev(void) | |||
| 1005 | { | 1008 | { |
| 1006 | ENGINE *engine = ENGINE_new(); | 1009 | ENGINE *engine = ENGINE_new(); |
| 1007 | struct syslog_data sd = SYSLOG_DATA_INIT; | 1010 | struct syslog_data sd = SYSLOG_DATA_INIT; |
| 1011 | int fd; | ||
| 1008 | 1012 | ||
| 1009 | if (engine == NULL) | 1013 | if (engine == NULL) |
| 1010 | return; | 1014 | return; |
| 1011 | 1015 | if ((fd = get_dev_crypto()) < 0) | |
| 1012 | |||
| 1013 | if (!check_dev_crypto()) { | ||
| 1014 | return; | 1016 | return; |
| 1015 | } | ||
| 1016 | 1017 | ||
| 1017 | /* | 1018 | /* |
| 1018 | * find out what asymmetric crypto algorithms we support | 1019 | * find out what asymmetric crypto algorithms we support |
| 1019 | */ | 1020 | */ |
| 1020 | if (ioctl(cryptodev_fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) { | 1021 | if (ioctl(fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) { |
| 1021 | syslog_r(LOG_ERR, &sd, "CIOCASYMFEAT failed (%m)"); | 1022 | syslog_r(LOG_ERR, &sd, "CIOCASYMFEAT failed (%m)"); |
| 1023 | close(fd); | ||
| 1022 | return; | 1024 | return; |
| 1023 | } | 1025 | } |
| 1026 | close(fd); | ||
| 1024 | 1027 | ||
| 1025 | if (!ENGINE_set_id(engine, "cryptodev") || | 1028 | if (!ENGINE_set_id(engine, "cryptodev") || |
| 1026 | !ENGINE_set_name(engine, "OpenBSD cryptodev engine") || | 1029 | !ENGINE_set_name(engine, "OpenBSD cryptodev engine") || |
| @@ -1084,4 +1087,3 @@ ENGINE_load_cryptodev(void) | |||
| 1084 | ENGINE_free(engine); | 1087 | ENGINE_free(engine); |
| 1085 | ERR_clear_error(); | 1088 | ERR_clear_error(); |
| 1086 | } | 1089 | } |
| 1087 | |||
