lib/krb5: krb5_init_creds_set_service fail if set_realm fails
[heimdal.git] / lib / hcrypto / evp-wincng.c
blob92974a91bb6b1065e384c6b2f3cb460598b9fa2f
1 /*
2 * Copyright (c) 2015, Secure Endpoints Inc.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 /* Windows CNG provider */
33 #include <config.h>
34 #include <roken.h>
35 #include <assert.h>
36 #include <versionsupport.h>
38 #include <evp.h>
39 #include <evp-wincng.h>
41 #include <bcrypt.h>
43 #ifndef BCRYPT_HASH_REUSABLE_FLAG
44 #define BCRYPT_HASH_REUSABLE_FLAG 0x00000020
45 #endif
48 * CNG cipher provider
51 struct wincng_key {
52 BCRYPT_KEY_HANDLE hKey;
53 UCHAR rgbKeyObject[1];
56 #define WINCNG_KEY_OBJECT_SIZE(ctx) \
57 ((ctx)->cipher->ctx_size - sizeof(struct wincng_key) + 1)
59 static int
60 wincng_do_cipher(EVP_CIPHER_CTX *ctx,
61 unsigned char *out,
62 const unsigned char *in,
63 unsigned int size)
65 struct wincng_key *cng = ctx->cipher_data;
66 NTSTATUS status;
67 ULONG cbResult;
69 assert(EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_STREAM_CIPHER ||
70 (size % ctx->cipher->block_size) == 0);
72 if (ctx->encrypt) {
73 status = BCryptEncrypt(cng->hKey,
74 (PUCHAR)in,
75 size,
76 NULL, /* pPaddingInfo */
77 ctx->cipher->iv_len ? ctx->iv : NULL,
78 ctx->cipher->iv_len,
79 out,
80 size,
81 &cbResult,
82 0);
83 } else {
84 status = BCryptDecrypt(cng->hKey,
85 (PUCHAR)in,
86 size,
87 NULL, /* pPaddingInfo */
88 ctx->cipher->iv_len ? ctx->iv : NULL,
89 ctx->cipher->iv_len,
90 out,
91 size,
92 &cbResult,
93 0);
96 return BCRYPT_SUCCESS(status) && cbResult == size;
99 static int
100 wincng_cleanup(EVP_CIPHER_CTX *ctx)
102 struct wincng_key *cng = ctx->cipher_data;
104 if (cng->hKey) {
105 BCryptDestroyKey(cng->hKey);
106 cng->hKey = (BCRYPT_KEY_HANDLE)0;
108 SecureZeroMemory(cng->rgbKeyObject, WINCNG_KEY_OBJECT_SIZE(ctx));
110 return 1;
113 static int
114 wincng_cipher_algorithm_init(EVP_CIPHER *cipher,
115 LPWSTR pszAlgId)
117 BCRYPT_ALG_HANDLE hAlgorithm = NULL;
118 NTSTATUS status;
119 LPCWSTR pszChainingMode;
120 ULONG cbKeyObject, cbChainingMode, cbData;
122 if (cipher->app_data)
123 return 1;
125 status = BCryptOpenAlgorithmProvider(&hAlgorithm,
126 pszAlgId,
127 NULL,
129 if (!BCRYPT_SUCCESS(status))
130 return 0;
132 status = BCryptGetProperty(hAlgorithm,
133 BCRYPT_OBJECT_LENGTH,
134 (PUCHAR)&cbKeyObject,
135 sizeof(ULONG),
136 &cbData,
138 if (!BCRYPT_SUCCESS(status)) {
139 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
140 return 0;
143 cipher->ctx_size = sizeof(struct wincng_key) + cbKeyObject - 1;
145 switch (cipher->flags & EVP_CIPH_MODE) {
146 case EVP_CIPH_CBC_MODE:
147 pszChainingMode = BCRYPT_CHAIN_MODE_CBC;
148 cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CBC);
149 break;
150 case EVP_CIPH_CFB8_MODE:
151 pszChainingMode = BCRYPT_CHAIN_MODE_CFB;
152 cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CFB);
153 break;
154 default:
155 pszChainingMode = NULL;
156 cbChainingMode = 0;
157 break;
160 if (cbChainingMode) {
161 status = BCryptSetProperty(hAlgorithm,
162 BCRYPT_CHAINING_MODE,
163 (PUCHAR)pszChainingMode,
164 cbChainingMode,
166 if (!BCRYPT_SUCCESS(status)) {
167 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
168 return 0;
172 if (wcscmp(pszAlgId, BCRYPT_RC2_ALGORITHM) == 0) {
173 ULONG cbEffectiveKeyLength = EVP_CIPHER_key_length(cipher) * 8;
175 status = BCryptSetProperty(hAlgorithm,
176 BCRYPT_EFFECTIVE_KEY_LENGTH,
177 (PUCHAR)&cbEffectiveKeyLength,
178 sizeof(cbEffectiveKeyLength),
180 if (!BCRYPT_SUCCESS(status)) {
181 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
182 return 0;
186 InterlockedCompareExchangePointerRelease(&cipher->app_data,
187 hAlgorithm, NULL);
188 return 1;
191 static int
192 wincng_key_init(EVP_CIPHER_CTX *ctx,
193 const unsigned char *key,
194 const unsigned char *iv,
195 int encp)
197 struct wincng_key *cng = ctx->cipher_data;
198 NTSTATUS status;
200 assert(cng != NULL);
201 assert(ctx->cipher != NULL);
203 if (ctx->cipher->app_data == NULL)
204 return 0;
206 wincng_cleanup(ctx);
209 * Note: ctx->key_len not EVP_CIPHER_CTX_key_length() for
210 * variable length key support.
212 status = BCryptGenerateSymmetricKey(ctx->cipher->app_data,
213 &cng->hKey,
214 cng->rgbKeyObject,
215 WINCNG_KEY_OBJECT_SIZE(ctx),
216 (PUCHAR)key,
217 ctx->key_len,
220 return BCRYPT_SUCCESS(status);
223 #define WINCNG_CIPHER_ALGORITHM(name, alg_id, block_size, key_len, \
224 iv_len, flags) \
226 static EVP_CIPHER \
227 wincng_##name = { \
228 0, \
229 block_size, \
230 key_len, \
231 iv_len, \
232 flags, \
233 wincng_key_init, \
234 wincng_do_cipher, \
235 wincng_cleanup, \
236 0, \
237 NULL, \
238 NULL, \
239 NULL, \
240 NULL \
241 }; \
243 const EVP_CIPHER * \
244 hc_EVP_wincng_##name(void) \
246 wincng_cipher_algorithm_init(&wincng_##name, alg_id); \
247 return wincng_##name.app_data ? &wincng_##name : NULL; \
250 #define WINCNG_CIPHER_ALGORITHM_CLEANUP(name) do { \
251 if (wincng_##name.app_data) { \
252 BCryptCloseAlgorithmProvider(wincng_##name.app_data, 0); \
253 wincng_##name.app_data = NULL; \
255 } while (0)
257 #define WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(name) \
259 const EVP_CIPHER * \
260 hc_EVP_wincng_##name(void) \
262 return NULL; \
266 * The triple DES cipher type (Windows CNG provider)
268 * @return the DES-EDE3-CBC EVP_CIPHER pointer.
270 * @ingroup hcrypto_evp
273 WINCNG_CIPHER_ALGORITHM(des_ede3_cbc,
274 BCRYPT_3DES_ALGORITHM,
278 EVP_CIPH_CBC_MODE);
281 * The DES cipher type (Windows CNG provider)
283 * @return the DES-CBC EVP_CIPHER pointer.
285 * @ingroup hcrypto_evp
288 WINCNG_CIPHER_ALGORITHM(des_cbc,
289 BCRYPT_DES_ALGORITHM,
293 EVP_CIPH_CBC_MODE);
296 * The AES-128 cipher type (Windows CNG provider)
298 * @return the AES-128-CBC EVP_CIPHER pointer.
300 * @ingroup hcrypto_evp
303 WINCNG_CIPHER_ALGORITHM(aes_128_cbc,
304 BCRYPT_AES_ALGORITHM,
308 EVP_CIPH_CBC_MODE);
311 * The AES-192 cipher type (Windows CNG provider)
313 * @return the AES-192-CBC EVP_CIPHER pointer.
315 * @ingroup hcrypto_evp
318 WINCNG_CIPHER_ALGORITHM(aes_192_cbc,
319 BCRYPT_AES_ALGORITHM,
323 EVP_CIPH_CBC_MODE);
326 * The AES-256 cipher type (Windows CNG provider)
328 * @return the AES-256-CBC EVP_CIPHER pointer.
330 * @ingroup hcrypto_evp
333 WINCNG_CIPHER_ALGORITHM(aes_256_cbc,
334 BCRYPT_AES_ALGORITHM,
338 EVP_CIPH_CBC_MODE);
341 * The AES-128 CFB8 cipher type (Windows CNG provider)
343 * @return the AES-128-CFB8 EVP_CIPHER pointer.
345 * @ingroup hcrypto_evp
348 WINCNG_CIPHER_ALGORITHM(aes_128_cfb8,
349 BCRYPT_AES_ALGORITHM,
353 EVP_CIPH_CFB8_MODE);
356 * The AES-192 CFB8 cipher type (Windows CNG provider)
358 * @return the AES-192-CFB8 EVP_CIPHER pointer.
360 * @ingroup hcrypto_evp
363 WINCNG_CIPHER_ALGORITHM(aes_192_cfb8,
364 BCRYPT_AES_ALGORITHM,
368 EVP_CIPH_CFB8_MODE);
371 * The AES-256 CFB8 cipher type (Windows CNG provider)
373 * @return the AES-256-CFB8 EVP_CIPHER pointer.
375 * @ingroup hcrypto_evp
378 WINCNG_CIPHER_ALGORITHM(aes_256_cfb8,
379 BCRYPT_AES_ALGORITHM,
383 EVP_CIPH_CFB8_MODE);
386 * The RC2 cipher type - Windows CNG
388 * @return the RC2 EVP_CIPHER pointer.
390 * @ingroup hcrypto_evp
393 WINCNG_CIPHER_ALGORITHM(rc2_cbc,
394 BCRYPT_RC2_ALGORITHM,
398 EVP_CIPH_CBC_MODE);
401 * The RC2-40 cipher type - Windows CNG
403 * @return the RC2-40 EVP_CIPHER pointer.
405 * @ingroup hcrypto_evp
408 WINCNG_CIPHER_ALGORITHM(rc2_40_cbc,
409 BCRYPT_RC2_ALGORITHM,
413 EVP_CIPH_CBC_MODE);
416 * The RC2-64 cipher type - Windows CNG
418 * @return the RC2-64 EVP_CIPHER pointer.
420 * @ingroup hcrypto_evp
423 WINCNG_CIPHER_ALGORITHM(rc2_64_cbc,
424 BCRYPT_RC2_ALGORITHM,
428 EVP_CIPH_CBC_MODE);
431 * The Camellia-128 cipher type - CommonCrypto
433 * @return the Camellia-128 EVP_CIPHER pointer.
435 * @ingroup hcrypto_evp
438 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_128_cbc);
441 * The Camellia-198 cipher type - CommonCrypto
443 * @return the Camellia-198 EVP_CIPHER pointer.
445 * @ingroup hcrypto_evp
448 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_192_cbc);
451 * The Camellia-256 cipher type - CommonCrypto
453 * @return the Camellia-256 EVP_CIPHER pointer.
455 * @ingroup hcrypto_evp
458 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_256_cbc);
461 * The RC4 cipher type (Windows CNG provider)
463 * @return the RC4 EVP_CIPHER pointer.
465 * @ingroup hcrypto_evp
468 WINCNG_CIPHER_ALGORITHM(rc4,
469 BCRYPT_RC4_ALGORITHM,
473 EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
476 * The RC4-40 cipher type (Windows CNG provider)
478 * @return the RC4 EVP_CIPHER pointer.
480 * @ingroup hcrypto_evp
483 WINCNG_CIPHER_ALGORITHM(rc4_40,
484 BCRYPT_RC4_ALGORITHM,
488 EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
490 static void
491 wincng_cipher_algorithm_cleanup(void)
493 WINCNG_CIPHER_ALGORITHM_CLEANUP(des_ede3_cbc);
494 WINCNG_CIPHER_ALGORITHM_CLEANUP(des_cbc);
495 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cbc);
496 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cbc);
497 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cbc);
498 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cfb8);
499 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cfb8);
500 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cfb8);
501 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_cbc);
502 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_40_cbc);
503 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_64_cbc);
504 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4);
505 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4_40);
509 * CNG digest provider
512 struct wincng_md_ctx {
513 BCRYPT_HASH_HANDLE hHash;
514 ULONG cbHashObject;
515 UCHAR rgbHashObject[1];
518 static BCRYPT_ALG_HANDLE
519 wincng_md_algorithm_init(EVP_MD *md,
520 LPCWSTR pszAlgId)
522 BCRYPT_ALG_HANDLE hAlgorithm;
523 NTSTATUS status;
524 ULONG cbHashObject, cbData;
525 ULONG cbHash = 0, cbBlock = 0;
527 status = BCryptOpenAlgorithmProvider(&hAlgorithm,
528 pszAlgId,
529 NULL,
531 if (!BCRYPT_SUCCESS(status))
532 return NULL;
534 status = BCryptGetProperty(hAlgorithm,
535 BCRYPT_HASH_LENGTH,
536 (PUCHAR)&cbHash,
537 sizeof(ULONG),
538 &cbData,
540 if (!BCRYPT_SUCCESS(status)) {
541 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
542 return NULL;
545 status = BCryptGetProperty(hAlgorithm,
546 BCRYPT_HASH_BLOCK_LENGTH,
547 (PUCHAR)&cbBlock,
548 sizeof(ULONG),
549 &cbData,
551 if (!BCRYPT_SUCCESS(status)) {
552 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
553 return NULL;
556 status = BCryptGetProperty(hAlgorithm,
557 BCRYPT_OBJECT_LENGTH,
558 (PUCHAR)&cbHashObject,
559 sizeof(ULONG),
560 &cbData,
562 if (!BCRYPT_SUCCESS(status)) {
563 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
564 return NULL;
567 md->hash_size = cbHash;
568 md->block_size = cbBlock;
569 md->ctx_size = sizeof(struct wincng_md_ctx) + cbHashObject - 1;
571 return hAlgorithm;
574 static int
575 wincng_md_cleanup(EVP_MD_CTX *ctx);
577 static int
578 wincng_md_hash_init(BCRYPT_ALG_HANDLE hAlgorithm,
579 EVP_MD_CTX *ctx)
581 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
582 NTSTATUS status;
583 ULONG cbData, dwFlags = 0;
585 if (IsWindows8OrGreaterCached()) {
586 if (cng->hHash)
587 return 1;
588 else
589 dwFlags |= BCRYPT_HASH_REUSABLE_FLAG;
590 } else
591 wincng_md_cleanup(ctx);
593 status = BCryptGetProperty(hAlgorithm,
594 BCRYPT_OBJECT_LENGTH,
595 (PUCHAR)&cng->cbHashObject,
596 sizeof(ULONG),
597 &cbData,
599 if (!BCRYPT_SUCCESS(status))
600 return 0;
602 status = BCryptCreateHash(hAlgorithm,
603 &cng->hHash,
604 cng->rgbHashObject,
605 cng->cbHashObject,
606 NULL,
608 dwFlags);
610 return BCRYPT_SUCCESS(status);
613 static int
614 wincng_md_update(EVP_MD_CTX *ctx,
615 const void *data,
616 size_t length)
618 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
619 NTSTATUS status;
621 status = BCryptHashData(cng->hHash, (PUCHAR)data, length, 0);
623 return BCRYPT_SUCCESS(status);
626 static int
627 wincng_md_final(void *digest,
628 EVP_MD_CTX *ctx)
630 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
631 NTSTATUS status;
632 ULONG cbHash, cbData;
634 status = BCryptGetProperty(cng->hHash,
635 BCRYPT_HASH_LENGTH,
636 (PUCHAR)&cbHash,
637 sizeof(DWORD),
638 &cbData,
640 if (!BCRYPT_SUCCESS(status))
641 return 0;
643 status = BCryptFinishHash(cng->hHash,
644 digest,
645 cbHash,
648 return BCRYPT_SUCCESS(status);
651 static int
652 wincng_md_cleanup(EVP_MD_CTX *ctx)
654 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
656 if (cng->hHash) {
657 BCryptDestroyHash(cng->hHash);
658 cng->hHash = (BCRYPT_HASH_HANDLE)0;
660 SecureZeroMemory(cng->rgbHashObject, cng->cbHashObject);
662 return 1;
665 #define WINCNG_MD_ALGORITHM(name, alg_id) \
667 static BCRYPT_ALG_HANDLE wincng_hAlgorithm_##name; \
669 static int wincng_##name##_init(EVP_MD_CTX *ctx) \
671 return wincng_md_hash_init(wincng_hAlgorithm_##name, ctx); \
674 const EVP_MD * \
675 hc_EVP_wincng_##name(void) \
677 static struct hc_evp_md name = { \
678 0, \
679 0, \
680 0, \
681 wincng_##name##_init, \
682 wincng_md_update, \
683 wincng_md_final, \
684 wincng_md_cleanup \
685 }; \
687 if (wincng_hAlgorithm_##name == NULL) { \
688 BCRYPT_ALG_HANDLE hAlgorithm = \
689 wincng_md_algorithm_init(&name, alg_id); \
690 InterlockedCompareExchangePointerRelease( \
691 &wincng_hAlgorithm_##name, hAlgorithm, NULL); \
693 return wincng_hAlgorithm_##name ? &name : NULL; \
696 #define WINCNG_MD_ALGORITHM_CLEANUP(name) do { \
697 if (wincng_hAlgorithm_##name) { \
698 BCryptCloseAlgorithmProvider(wincng_hAlgorithm_##name, 0); \
699 wincng_hAlgorithm_##name = NULL; \
701 } while (0)
703 WINCNG_MD_ALGORITHM(md2, BCRYPT_MD2_ALGORITHM);
704 WINCNG_MD_ALGORITHM(md4, BCRYPT_MD4_ALGORITHM);
705 WINCNG_MD_ALGORITHM(md5, BCRYPT_MD5_ALGORITHM);
706 WINCNG_MD_ALGORITHM(sha1, BCRYPT_SHA1_ALGORITHM);
707 WINCNG_MD_ALGORITHM(sha256, BCRYPT_SHA256_ALGORITHM);
708 WINCNG_MD_ALGORITHM(sha384, BCRYPT_SHA384_ALGORITHM);
709 WINCNG_MD_ALGORITHM(sha512, BCRYPT_SHA512_ALGORITHM);
711 static void
712 wincng_md_algorithm_cleanup(void)
714 WINCNG_MD_ALGORITHM_CLEANUP(md2);
715 WINCNG_MD_ALGORITHM_CLEANUP(md4);
716 WINCNG_MD_ALGORITHM_CLEANUP(md5);
717 WINCNG_MD_ALGORITHM_CLEANUP(sha1);
718 WINCNG_MD_ALGORITHM_CLEANUP(sha256);
719 WINCNG_MD_ALGORITHM_CLEANUP(sha384);
720 WINCNG_MD_ALGORITHM_CLEANUP(sha512);
723 void _hc_wincng_cleanup(void)
725 wincng_md_algorithm_cleanup();
726 wincng_cipher_algorithm_cleanup();