1 /*
2 * Copyright (C) 2013-2020 Marc Hoersken <info@marc-hoersken.de>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms,
6 * with or without modification, are permitted provided
7 * that the following conditions are met:
8 *
9 * Redistributions of source code must retain the above
10 * copyright notice, this list of conditions and the
11 * following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
17 *
18 * Neither the name of the copyright holder nor the names
19 * of any other contributors may be used to endorse or
20 * promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 */
38
39 #include "libssh2_priv.h"
40
41 #ifdef LIBSSH2_WINCNG /* compile only if we build with wincng */
42
43 /* required for cross-compilation against the w64 mingw-runtime package */
44 #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600)
45 #undef _WIN32_WINNT
46 #endif
47 #ifndef _WIN32_WINNT
48 #define _WIN32_WINNT 0x0600
49 #endif
50
51 /* specify the required libraries for dependencies using MSVC */
52 #ifdef _MSC_VER
53 #pragma comment(lib, "bcrypt.lib")
54 #ifdef HAVE_LIBCRYPT32
55 #pragma comment(lib, "crypt32.lib")
56 #endif
57 #endif
58
59 #include <windows.h>
60 #include <bcrypt.h>
61 #include <ntstatus.h>
62 #include <math.h>
63 #include "misc.h"
64
65 #ifdef HAVE_STDLIB_H
66 #include <stdlib.h>
67 #endif
68 #ifdef HAVE_LIBCRYPT32
69 #include <wincrypt.h>
70 #endif
71
72 #define PEM_RSA_HEADER "-----BEGIN RSA PRIVATE KEY-----"
73 #define PEM_RSA_FOOTER "-----END RSA PRIVATE KEY-----"
74 #define PEM_DSA_HEADER "-----BEGIN DSA PRIVATE KEY-----"
75 #define PEM_DSA_FOOTER "-----END DSA PRIVATE KEY-----"
76
77
78 /*******************************************************************/
79 /*
80 * Windows CNG backend: Missing definitions (for MinGW[-w64])
81 */
82 #ifndef BCRYPT_SUCCESS
83 #define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
84 #endif
85
86 #ifndef BCRYPT_RNG_ALGORITHM
87 #define BCRYPT_RNG_ALGORITHM L"RNG"
88 #endif
89
90 #ifndef BCRYPT_MD5_ALGORITHM
91 #define BCRYPT_MD5_ALGORITHM L"MD5"
92 #endif
93
94 #ifndef BCRYPT_SHA1_ALGORITHM
95 #define BCRYPT_SHA1_ALGORITHM L"SHA1"
96 #endif
97
98 #ifndef BCRYPT_SHA256_ALGORITHM
99 #define BCRYPT_SHA256_ALGORITHM L"SHA256"
100 #endif
101
102 #ifndef BCRYPT_SHA384_ALGORITHM
103 #define BCRYPT_SHA384_ALGORITHM L"SHA384"
104 #endif
105
106 #ifndef BCRYPT_SHA512_ALGORITHM
107 #define BCRYPT_SHA512_ALGORITHM L"SHA512"
108 #endif
109
110 #ifndef BCRYPT_RSA_ALGORITHM
111 #define BCRYPT_RSA_ALGORITHM L"RSA"
112 #endif
113
114 #ifndef BCRYPT_DSA_ALGORITHM
115 #define BCRYPT_DSA_ALGORITHM L"DSA"
116 #endif
117
118 #ifndef BCRYPT_AES_ALGORITHM
119 #define BCRYPT_AES_ALGORITHM L"AES"
120 #endif
121
122 #ifndef BCRYPT_RC4_ALGORITHM
123 #define BCRYPT_RC4_ALGORITHM L"RC4"
124 #endif
125
126 #ifndef BCRYPT_3DES_ALGORITHM
127 #define BCRYPT_3DES_ALGORITHM L"3DES"
128 #endif
129
130 #ifndef BCRYPT_DH_ALGORITHM
131 #define BCRYPT_DH_ALGORITHM L"DH"
132 #endif
133
134 /* BCRYPT_KDF_RAW_SECRET is available from Windows 8.1 and onwards */
135 #ifndef BCRYPT_KDF_RAW_SECRET
136 #define BCRYPT_KDF_RAW_SECRET L"TRUNCATE"
137 #endif
138
139 #ifndef BCRYPT_ALG_HANDLE_HMAC_FLAG
140 #define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008
141 #endif
142
143 #ifndef BCRYPT_DSA_PUBLIC_BLOB
144 #define BCRYPT_DSA_PUBLIC_BLOB L"DSAPUBLICBLOB"
145 #endif
146
147 #ifndef BCRYPT_DSA_PUBLIC_MAGIC
148 #define BCRYPT_DSA_PUBLIC_MAGIC 0x42505344 /* DSPB */
149 #endif
150
151 #ifndef BCRYPT_DSA_PRIVATE_BLOB
152 #define BCRYPT_DSA_PRIVATE_BLOB L"DSAPRIVATEBLOB"
153 #endif
154
155 #ifndef BCRYPT_DSA_PRIVATE_MAGIC
156 #define BCRYPT_DSA_PRIVATE_MAGIC 0x56505344 /* DSPV */
157 #endif
158
159 #ifndef BCRYPT_RSAPUBLIC_BLOB
160 #define BCRYPT_RSAPUBLIC_BLOB L"RSAPUBLICBLOB"
161 #endif
162
163 #ifndef BCRYPT_RSAPUBLIC_MAGIC
164 #define BCRYPT_RSAPUBLIC_MAGIC 0x31415352 /* RSA1 */
165 #endif
166
167 #ifndef BCRYPT_RSAFULLPRIVATE_BLOB
168 #define BCRYPT_RSAFULLPRIVATE_BLOB L"RSAFULLPRIVATEBLOB"
169 #endif
170
171 #ifndef BCRYPT_RSAFULLPRIVATE_MAGIC
172 #define BCRYPT_RSAFULLPRIVATE_MAGIC 0x33415352 /* RSA3 */
173 #endif
174
175 #ifndef BCRYPT_KEY_DATA_BLOB
176 #define BCRYPT_KEY_DATA_BLOB L"KeyDataBlob"
177 #endif
178
179 #ifndef BCRYPT_MESSAGE_BLOCK_LENGTH
180 #define BCRYPT_MESSAGE_BLOCK_LENGTH L"MessageBlockLength"
181 #endif
182
183 #ifndef BCRYPT_NO_KEY_VALIDATION
184 #define BCRYPT_NO_KEY_VALIDATION 0x00000008
185 #endif
186
187 #ifndef BCRYPT_BLOCK_PADDING
188 #define BCRYPT_BLOCK_PADDING 0x00000001
189 #endif
190
191 #ifndef BCRYPT_PAD_NONE
192 #define BCRYPT_PAD_NONE 0x00000001
193 #endif
194
195 #ifndef BCRYPT_PAD_PKCS1
196 #define BCRYPT_PAD_PKCS1 0x00000002
197 #endif
198
199 #ifndef BCRYPT_PAD_OAEP
200 #define BCRYPT_PAD_OAEP 0x00000004
201 #endif
202
203 #ifndef BCRYPT_PAD_PSS
204 #define BCRYPT_PAD_PSS 0x00000008
205 #endif
206
207 #ifndef CRYPT_STRING_ANY
208 #define CRYPT_STRING_ANY 0x00000007
209 #endif
210
211 #ifndef LEGACY_RSAPRIVATE_BLOB
212 #define LEGACY_RSAPRIVATE_BLOB L"CAPIPRIVATEBLOB"
213 #endif
214
215 #ifndef PKCS_RSA_PRIVATE_KEY
216 #define PKCS_RSA_PRIVATE_KEY (LPCSTR)43
217 #endif
218
219
220 /*******************************************************************/
221 /*
222 * Windows CNG backend: Generic functions
223 */
224
225 struct _libssh2_wincng_ctx _libssh2_wincng;
226
227 void
_libssh2_wincng_init(void)228 _libssh2_wincng_init(void)
229 {
230 int ret;
231
232 memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng));
233
234 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG,
235 BCRYPT_RNG_ALGORITHM, NULL, 0);
236 if(!BCRYPT_SUCCESS(ret)) {
237 _libssh2_wincng.hAlgRNG = NULL;
238 }
239
240 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5,
241 BCRYPT_MD5_ALGORITHM, NULL, 0);
242 if(!BCRYPT_SUCCESS(ret)) {
243 _libssh2_wincng.hAlgHashMD5 = NULL;
244 }
245 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1,
246 BCRYPT_SHA1_ALGORITHM, NULL, 0);
247 if(!BCRYPT_SUCCESS(ret)) {
248 _libssh2_wincng.hAlgHashSHA1 = NULL;
249 }
250 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA256,
251 BCRYPT_SHA256_ALGORITHM, NULL, 0);
252 if(!BCRYPT_SUCCESS(ret)) {
253 _libssh2_wincng.hAlgHashSHA256 = NULL;
254 }
255 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA384,
256 BCRYPT_SHA384_ALGORITHM, NULL, 0);
257 if(!BCRYPT_SUCCESS(ret)) {
258 _libssh2_wincng.hAlgHashSHA384 = NULL;
259 }
260 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512,
261 BCRYPT_SHA512_ALGORITHM, NULL, 0);
262 if(!BCRYPT_SUCCESS(ret)) {
263 _libssh2_wincng.hAlgHashSHA512 = NULL;
264 }
265
266 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5,
267 BCRYPT_MD5_ALGORITHM, NULL,
268 BCRYPT_ALG_HANDLE_HMAC_FLAG);
269 if(!BCRYPT_SUCCESS(ret)) {
270 _libssh2_wincng.hAlgHmacMD5 = NULL;
271 }
272 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1,
273 BCRYPT_SHA1_ALGORITHM, NULL,
274 BCRYPT_ALG_HANDLE_HMAC_FLAG);
275 if(!BCRYPT_SUCCESS(ret)) {
276 _libssh2_wincng.hAlgHmacSHA1 = NULL;
277 }
278 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA256,
279 BCRYPT_SHA256_ALGORITHM, NULL,
280 BCRYPT_ALG_HANDLE_HMAC_FLAG);
281 if(!BCRYPT_SUCCESS(ret)) {
282 _libssh2_wincng.hAlgHmacSHA256 = NULL;
283 }
284 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA384,
285 BCRYPT_SHA384_ALGORITHM, NULL,
286 BCRYPT_ALG_HANDLE_HMAC_FLAG);
287 if(!BCRYPT_SUCCESS(ret)) {
288 _libssh2_wincng.hAlgHmacSHA384 = NULL;
289 }
290 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512,
291 BCRYPT_SHA512_ALGORITHM, NULL,
292 BCRYPT_ALG_HANDLE_HMAC_FLAG);
293 if(!BCRYPT_SUCCESS(ret)) {
294 _libssh2_wincng.hAlgHmacSHA512 = NULL;
295 }
296
297 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA,
298 BCRYPT_RSA_ALGORITHM, NULL, 0);
299 if(!BCRYPT_SUCCESS(ret)) {
300 _libssh2_wincng.hAlgRSA = NULL;
301 }
302 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA,
303 BCRYPT_DSA_ALGORITHM, NULL, 0);
304 if(!BCRYPT_SUCCESS(ret)) {
305 _libssh2_wincng.hAlgDSA = NULL;
306 }
307
308 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_CBC,
309 BCRYPT_AES_ALGORITHM, NULL, 0);
310 if(BCRYPT_SUCCESS(ret)) {
311 ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_CBC,
312 BCRYPT_CHAINING_MODE,
313 (PBYTE)BCRYPT_CHAIN_MODE_CBC,
314 sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
315 if(!BCRYPT_SUCCESS(ret)) {
316 ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0);
317 if(BCRYPT_SUCCESS(ret)) {
318 _libssh2_wincng.hAlgAES_CBC = NULL;
319 }
320 }
321 }
322
323 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_ECB,
324 BCRYPT_AES_ALGORITHM, NULL, 0);
325 if(BCRYPT_SUCCESS(ret)) {
326 ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_ECB,
327 BCRYPT_CHAINING_MODE,
328 (PBYTE)BCRYPT_CHAIN_MODE_ECB,
329 sizeof(BCRYPT_CHAIN_MODE_ECB), 0);
330 if(!BCRYPT_SUCCESS(ret)) {
331 ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_ECB, 0);
332 if(BCRYPT_SUCCESS(ret)) {
333 _libssh2_wincng.hAlgAES_ECB = NULL;
334 }
335 }
336 }
337
338 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRC4_NA,
339 BCRYPT_RC4_ALGORITHM, NULL, 0);
340 if(BCRYPT_SUCCESS(ret)) {
341 ret = BCryptSetProperty(_libssh2_wincng.hAlgRC4_NA,
342 BCRYPT_CHAINING_MODE,
343 (PBYTE)BCRYPT_CHAIN_MODE_NA,
344 sizeof(BCRYPT_CHAIN_MODE_NA), 0);
345 if(!BCRYPT_SUCCESS(ret)) {
346 ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0);
347 if(BCRYPT_SUCCESS(ret)) {
348 _libssh2_wincng.hAlgRC4_NA = NULL;
349 }
350 }
351 }
352
353 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlg3DES_CBC,
354 BCRYPT_3DES_ALGORITHM, NULL, 0);
355 if(BCRYPT_SUCCESS(ret)) {
356 ret = BCryptSetProperty(_libssh2_wincng.hAlg3DES_CBC,
357 BCRYPT_CHAINING_MODE,
358 (PBYTE)BCRYPT_CHAIN_MODE_CBC,
359 sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
360 if(!BCRYPT_SUCCESS(ret)) {
361 ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC,
362 0);
363 if(BCRYPT_SUCCESS(ret)) {
364 _libssh2_wincng.hAlg3DES_CBC = NULL;
365 }
366 }
367 }
368
369 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDH,
370 BCRYPT_DH_ALGORITHM, NULL, 0);
371 if(!BCRYPT_SUCCESS(ret)) {
372 _libssh2_wincng.hAlgDH = NULL;
373 }
374 }
375
376 void
_libssh2_wincng_free(void)377 _libssh2_wincng_free(void)
378 {
379 if(_libssh2_wincng.hAlgRNG)
380 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRNG, 0);
381 if(_libssh2_wincng.hAlgHashMD5)
382 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashMD5, 0);
383 if(_libssh2_wincng.hAlgHashSHA1)
384 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0);
385 if(_libssh2_wincng.hAlgHashSHA256)
386 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA256, 0);
387 if(_libssh2_wincng.hAlgHashSHA384)
388 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA384, 0);
389 if(_libssh2_wincng.hAlgHashSHA512)
390 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA512, 0);
391 if(_libssh2_wincng.hAlgHmacMD5)
392 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacMD5, 0);
393 if(_libssh2_wincng.hAlgHmacSHA1)
394 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0);
395 if(_libssh2_wincng.hAlgHmacSHA256)
396 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA256, 0);
397 if(_libssh2_wincng.hAlgHmacSHA384)
398 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA384, 0);
399 if(_libssh2_wincng.hAlgHmacSHA512)
400 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA512, 0);
401 if(_libssh2_wincng.hAlgRSA)
402 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRSA, 0);
403 if(_libssh2_wincng.hAlgDSA)
404 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDSA, 0);
405 if(_libssh2_wincng.hAlgAES_CBC)
406 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0);
407 if(_libssh2_wincng.hAlgRC4_NA)
408 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0);
409 if(_libssh2_wincng.hAlg3DES_CBC)
410 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0);
411 if(_libssh2_wincng.hAlgDH)
412 (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDH, 0);
413
414 memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng));
415 }
416
417 int
_libssh2_wincng_random(void * buf,int len)418 _libssh2_wincng_random(void *buf, int len)
419 {
420 int ret;
421
422 ret = BCryptGenRandom(_libssh2_wincng.hAlgRNG, buf, len, 0);
423
424 return BCRYPT_SUCCESS(ret) ? 0 : -1;
425 }
426
427 static void
_libssh2_wincng_safe_free(void * buf,int len)428 _libssh2_wincng_safe_free(void *buf, int len)
429 {
430 #ifndef LIBSSH2_CLEAR_MEMORY
431 (void)len;
432 #endif
433
434 if(!buf)
435 return;
436
437 #ifdef LIBSSH2_CLEAR_MEMORY
438 if(len > 0)
439 SecureZeroMemory(buf, len);
440 #endif
441
442 free(buf);
443 }
444
445 /* Copy a big endian set of bits from src to dest.
446 * if the size of src is smaller than dest then pad the "left" (MSB)
447 * end with zeroes and copy the bits into the "right" (LSB) end. */
448 static void
memcpy_with_be_padding(unsigned char * dest,unsigned long dest_len,unsigned char * src,unsigned long src_len)449 memcpy_with_be_padding(unsigned char *dest, unsigned long dest_len,
450 unsigned char *src, unsigned long src_len)
451 {
452 if(dest_len > src_len) {
453 memset(dest, 0, dest_len - src_len);
454 }
455 memcpy((dest + dest_len) - src_len, src, src_len);
456 }
457
458 static int
round_down(int number,int multiple)459 round_down(int number, int multiple)
460 {
461 return (number / multiple) * multiple;
462 }
463
464 /*******************************************************************/
465 /*
466 * Windows CNG backend: Hash functions
467 */
468
469 int
_libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx * ctx,BCRYPT_ALG_HANDLE hAlg,unsigned long hashlen,unsigned char * key,unsigned long keylen)470 _libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx,
471 BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen,
472 unsigned char *key, unsigned long keylen)
473 {
474 BCRYPT_HASH_HANDLE hHash;
475 unsigned char *pbHashObject;
476 unsigned long dwHashObject, dwHash, cbData;
477 int ret;
478
479 ret = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH,
480 (unsigned char *)&dwHash,
481 sizeof(dwHash),
482 &cbData, 0);
483 if((!BCRYPT_SUCCESS(ret)) || dwHash != hashlen) {
484 return -1;
485 }
486
487 ret = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH,
488 (unsigned char *)&dwHashObject,
489 sizeof(dwHashObject),
490 &cbData, 0);
491 if(!BCRYPT_SUCCESS(ret)) {
492 return -1;
493 }
494
495 pbHashObject = malloc(dwHashObject);
496 if(!pbHashObject) {
497 return -1;
498 }
499
500
501 ret = BCryptCreateHash(hAlg, &hHash,
502 pbHashObject, dwHashObject,
503 key, keylen, 0);
504 if(!BCRYPT_SUCCESS(ret)) {
505 _libssh2_wincng_safe_free(pbHashObject, dwHashObject);
506 return -1;
507 }
508
509
510 ctx->hHash = hHash;
511 ctx->pbHashObject = pbHashObject;
512 ctx->dwHashObject = dwHashObject;
513 ctx->cbHash = dwHash;
514
515 return 0;
516 }
517
518 int
_libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx * ctx,const unsigned char * data,unsigned long datalen)519 _libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx,
520 const unsigned char *data, unsigned long datalen)
521 {
522 int ret;
523
524 ret = BCryptHashData(ctx->hHash, (unsigned char *)data, datalen, 0);
525
526 return BCRYPT_SUCCESS(ret) ? 0 : -1;
527 }
528
529 int
_libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx * ctx,unsigned char * hash)530 _libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx,
531 unsigned char *hash)
532 {
533 int ret;
534
535 ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0);
536
537 BCryptDestroyHash(ctx->hHash);
538 ctx->hHash = NULL;
539
540 _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject);
541 ctx->pbHashObject = NULL;
542 ctx->dwHashObject = 0;
543
544 return BCRYPT_SUCCESS(ret) ? 0 : -1;
545 }
546
547 int
_libssh2_wincng_hash(unsigned char * data,unsigned long datalen,BCRYPT_ALG_HANDLE hAlg,unsigned char * hash,unsigned long hashlen)548 _libssh2_wincng_hash(unsigned char *data, unsigned long datalen,
549 BCRYPT_ALG_HANDLE hAlg,
550 unsigned char *hash, unsigned long hashlen)
551 {
552 _libssh2_wincng_hash_ctx ctx;
553 int ret;
554
555 ret = _libssh2_wincng_hash_init(&ctx, hAlg, hashlen, NULL, 0);
556 if(!ret) {
557 ret = _libssh2_wincng_hash_update(&ctx, data, datalen);
558 ret |= _libssh2_wincng_hash_final(&ctx, hash);
559 }
560
561 return ret;
562 }
563
564
565 /*******************************************************************/
566 /*
567 * Windows CNG backend: HMAC functions
568 */
569
570 int
_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx * ctx,unsigned char * hash)571 _libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx,
572 unsigned char *hash)
573 {
574 int ret;
575
576 ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0);
577
578 return BCRYPT_SUCCESS(ret) ? 0 : -1;
579 }
580
581 void
_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx * ctx)582 _libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx)
583 {
584 BCryptDestroyHash(ctx->hHash);
585 ctx->hHash = NULL;
586
587 _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject);
588 ctx->pbHashObject = NULL;
589 ctx->dwHashObject = 0;
590 }
591
592
593 /*******************************************************************/
594 /*
595 * Windows CNG backend: Key functions
596 */
597
598 int
_libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx * ctx,const unsigned char * sig,unsigned long sig_len,const unsigned char * m,unsigned long m_len,unsigned long flags)599 _libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx,
600 const unsigned char *sig,
601 unsigned long sig_len,
602 const unsigned char *m,
603 unsigned long m_len,
604 unsigned long flags)
605 {
606 BCRYPT_PKCS1_PADDING_INFO paddingInfoPKCS1;
607 void *pPaddingInfo;
608 unsigned char *data, *hash;
609 unsigned long datalen, hashlen;
610 int ret;
611
612 datalen = m_len;
613 data = malloc(datalen);
614 if(!data) {
615 return -1;
616 }
617
618 hashlen = SHA_DIGEST_LENGTH;
619 hash = malloc(hashlen);
620 if(!hash) {
621 free(data);
622 return -1;
623 }
624
625 memcpy(data, m, datalen);
626
627 ret = _libssh2_wincng_hash(data, datalen,
628 _libssh2_wincng.hAlgHashSHA1,
629 hash, hashlen);
630
631 _libssh2_wincng_safe_free(data, datalen);
632
633 if(ret) {
634 _libssh2_wincng_safe_free(hash, hashlen);
635 return -1;
636 }
637
638 datalen = sig_len;
639 data = malloc(datalen);
640 if(!data) {
641 _libssh2_wincng_safe_free(hash, hashlen);
642 return -1;
643 }
644
645 if(flags & BCRYPT_PAD_PKCS1) {
646 paddingInfoPKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM;
647 pPaddingInfo = &paddingInfoPKCS1;
648 }
649 else
650 pPaddingInfo = NULL;
651
652 memcpy(data, sig, datalen);
653
654 ret = BCryptVerifySignature(ctx->hKey, pPaddingInfo,
655 hash, hashlen, data, datalen, flags);
656
657 _libssh2_wincng_safe_free(hash, hashlen);
658 _libssh2_wincng_safe_free(data, datalen);
659
660 return BCRYPT_SUCCESS(ret) ? 0 : -1;
661 }
662
663 #ifdef HAVE_LIBCRYPT32
664 static int
_libssh2_wincng_load_pem(LIBSSH2_SESSION * session,const char * filename,const char * passphrase,const char * headerbegin,const char * headerend,unsigned char ** data,unsigned int * datalen)665 _libssh2_wincng_load_pem(LIBSSH2_SESSION *session,
666 const char *filename,
667 const char *passphrase,
668 const char *headerbegin,
669 const char *headerend,
670 unsigned char **data,
671 unsigned int *datalen)
672 {
673 FILE *fp;
674 int ret;
675
676 fp = fopen(filename, FOPEN_READTEXT);
677 if(!fp) {
678 return -1;
679 }
680
681 ret = _libssh2_pem_parse(session, headerbegin, headerend,
682 passphrase,
683 fp, data, datalen);
684
685 fclose(fp);
686
687 return ret;
688 }
689
690 static int
_libssh2_wincng_load_private(LIBSSH2_SESSION * session,const char * filename,const char * passphrase,unsigned char ** ppbEncoded,unsigned long * pcbEncoded,int tryLoadRSA,int tryLoadDSA)691 _libssh2_wincng_load_private(LIBSSH2_SESSION *session,
692 const char *filename,
693 const char *passphrase,
694 unsigned char **ppbEncoded,
695 unsigned long *pcbEncoded,
696 int tryLoadRSA, int tryLoadDSA)
697 {
698 unsigned char *data = NULL;
699 unsigned int datalen = 0;
700 int ret = -1;
701
702 if(ret && tryLoadRSA) {
703 ret = _libssh2_wincng_load_pem(session, filename, passphrase,
704 PEM_RSA_HEADER, PEM_RSA_FOOTER,
705 &data, &datalen);
706 }
707
708 if(ret && tryLoadDSA) {
709 ret = _libssh2_wincng_load_pem(session, filename, passphrase,
710 PEM_DSA_HEADER, PEM_DSA_FOOTER,
711 &data, &datalen);
712 }
713
714 if(!ret) {
715 *ppbEncoded = data;
716 *pcbEncoded = datalen;
717 }
718
719 return ret;
720 }
721
722 static int
_libssh2_wincng_load_private_memory(LIBSSH2_SESSION * session,const char * privatekeydata,size_t privatekeydata_len,const char * passphrase,unsigned char ** ppbEncoded,unsigned long * pcbEncoded,int tryLoadRSA,int tryLoadDSA)723 _libssh2_wincng_load_private_memory(LIBSSH2_SESSION *session,
724 const char *privatekeydata,
725 size_t privatekeydata_len,
726 const char *passphrase,
727 unsigned char **ppbEncoded,
728 unsigned long *pcbEncoded,
729 int tryLoadRSA, int tryLoadDSA)
730 {
731 unsigned char *data = NULL;
732 unsigned int datalen = 0;
733 int ret = -1;
734
735 (void)passphrase;
736
737 if(ret && tryLoadRSA) {
738 ret = _libssh2_pem_parse_memory(session,
739 PEM_RSA_HEADER, PEM_RSA_FOOTER,
740 privatekeydata, privatekeydata_len,
741 &data, &datalen);
742 }
743
744 if(ret && tryLoadDSA) {
745 ret = _libssh2_pem_parse_memory(session,
746 PEM_DSA_HEADER, PEM_DSA_FOOTER,
747 privatekeydata, privatekeydata_len,
748 &data, &datalen);
749 }
750
751 if(!ret) {
752 *ppbEncoded = data;
753 *pcbEncoded = datalen;
754 }
755
756 return ret;
757 }
758
759 static int
_libssh2_wincng_asn_decode(unsigned char * pbEncoded,unsigned long cbEncoded,LPCSTR lpszStructType,unsigned char ** ppbDecoded,unsigned long * pcbDecoded)760 _libssh2_wincng_asn_decode(unsigned char *pbEncoded,
761 unsigned long cbEncoded,
762 LPCSTR lpszStructType,
763 unsigned char **ppbDecoded,
764 unsigned long *pcbDecoded)
765 {
766 unsigned char *pbDecoded = NULL;
767 unsigned long cbDecoded = 0;
768 int ret;
769
770 ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
771 lpszStructType,
772 pbEncoded, cbEncoded, 0, NULL,
773 NULL, &cbDecoded);
774 if(!ret) {
775 return -1;
776 }
777
778 pbDecoded = malloc(cbDecoded);
779 if(!pbDecoded) {
780 return -1;
781 }
782
783 ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
784 lpszStructType,
785 pbEncoded, cbEncoded, 0, NULL,
786 pbDecoded, &cbDecoded);
787 if(!ret) {
788 _libssh2_wincng_safe_free(pbDecoded, cbDecoded);
789 return -1;
790 }
791
792
793 *ppbDecoded = pbDecoded;
794 *pcbDecoded = cbDecoded;
795
796 return 0;
797 }
798
799 static int
_libssh2_wincng_bn_ltob(unsigned char * pbInput,unsigned long cbInput,unsigned char ** ppbOutput,unsigned long * pcbOutput)800 _libssh2_wincng_bn_ltob(unsigned char *pbInput,
801 unsigned long cbInput,
802 unsigned char **ppbOutput,
803 unsigned long *pcbOutput)
804 {
805 unsigned char *pbOutput;
806 unsigned long cbOutput, index, offset, length;
807
808 if(cbInput < 1) {
809 return 0;
810 }
811
812 offset = 0;
813 length = cbInput - 1;
814 cbOutput = cbInput;
815 if(pbInput[length] & (1 << 7)) {
816 offset++;
817 cbOutput += offset;
818 }
819
820 pbOutput = (unsigned char *)malloc(cbOutput);
821 if(!pbOutput) {
822 return -1;
823 }
824
825 pbOutput[0] = 0;
826 for(index = 0; ((index + offset) < cbOutput)
827 && (index < cbInput); index++) {
828 pbOutput[index + offset] = pbInput[length - index];
829 }
830
831
832 *ppbOutput = pbOutput;
833 *pcbOutput = cbOutput;
834
835 return 0;
836 }
837
838 static int
_libssh2_wincng_asn_decode_bn(unsigned char * pbEncoded,unsigned long cbEncoded,unsigned char ** ppbDecoded,unsigned long * pcbDecoded)839 _libssh2_wincng_asn_decode_bn(unsigned char *pbEncoded,
840 unsigned long cbEncoded,
841 unsigned char **ppbDecoded,
842 unsigned long *pcbDecoded)
843 {
844 unsigned char *pbDecoded = NULL, *pbInteger;
845 unsigned long cbDecoded = 0, cbInteger;
846 int ret;
847
848 ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded,
849 X509_MULTI_BYTE_UINT,
850 &pbInteger, &cbInteger);
851 if(!ret) {
852 ret = _libssh2_wincng_bn_ltob(((PCRYPT_DATA_BLOB)pbInteger)->pbData,
853 ((PCRYPT_DATA_BLOB)pbInteger)->cbData,
854 &pbDecoded, &cbDecoded);
855 if(!ret) {
856 *ppbDecoded = pbDecoded;
857 *pcbDecoded = cbDecoded;
858 }
859 _libssh2_wincng_safe_free(pbInteger, cbInteger);
860 }
861
862 return ret;
863 }
864
865 static int
_libssh2_wincng_asn_decode_bns(unsigned char * pbEncoded,unsigned long cbEncoded,unsigned char *** prpbDecoded,unsigned long ** prcbDecoded,unsigned long * pcbCount)866 _libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded,
867 unsigned long cbEncoded,
868 unsigned char ***prpbDecoded,
869 unsigned long **prcbDecoded,
870 unsigned long *pcbCount)
871 {
872 PCRYPT_DER_BLOB pBlob;
873 unsigned char *pbDecoded, **rpbDecoded;
874 unsigned long cbDecoded, *rcbDecoded, index, length;
875 int ret;
876
877 ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded,
878 X509_SEQUENCE_OF_ANY,
879 &pbDecoded, &cbDecoded);
880 if(!ret) {
881 length = ((PCRYPT_DATA_BLOB)pbDecoded)->cbData;
882
883 rpbDecoded = malloc(sizeof(PBYTE) * length);
884 if(rpbDecoded) {
885 rcbDecoded = malloc(sizeof(DWORD) * length);
886 if(rcbDecoded) {
887 for(index = 0; index < length; index++) {
888 pBlob = &((PCRYPT_DER_BLOB)
889 ((PCRYPT_DATA_BLOB)pbDecoded)->pbData)[index];
890 ret = _libssh2_wincng_asn_decode_bn(pBlob->pbData,
891 pBlob->cbData,
892 &rpbDecoded[index],
893 &rcbDecoded[index]);
894 if(ret)
895 break;
896 }
897
898 if(!ret) {
899 *prpbDecoded = rpbDecoded;
900 *prcbDecoded = rcbDecoded;
901 *pcbCount = length;
902 }
903 else {
904 for(length = 0; length < index; length++) {
905 _libssh2_wincng_safe_free(rpbDecoded[length],
906 rcbDecoded[length]);
907 rpbDecoded[length] = NULL;
908 rcbDecoded[length] = 0;
909 }
910 free(rpbDecoded);
911 free(rcbDecoded);
912 }
913 }
914 else {
915 free(rpbDecoded);
916 ret = -1;
917 }
918 }
919 else {
920 ret = -1;
921 }
922
923 _libssh2_wincng_safe_free(pbDecoded, cbDecoded);
924 }
925
926 return ret;
927 }
928 #endif /* HAVE_LIBCRYPT32 */
929
930 static unsigned long
_libssh2_wincng_bn_size(const unsigned char * bignum,unsigned long length)931 _libssh2_wincng_bn_size(const unsigned char *bignum,
932 unsigned long length)
933 {
934 unsigned long offset;
935
936 if(!bignum)
937 return 0;
938
939 length--;
940
941 offset = 0;
942 while(!(*(bignum + offset)) && (offset < length))
943 offset++;
944
945 length++;
946
947 return length - offset;
948 }
949
950
951 /*******************************************************************/
952 /*
953 * Windows CNG backend: RSA functions
954 */
955
956 int
_libssh2_wincng_rsa_new(libssh2_rsa_ctx ** rsa,const unsigned char * edata,unsigned long elen,const unsigned char * ndata,unsigned long nlen,const unsigned char * ddata,unsigned long dlen,const unsigned char * pdata,unsigned long plen,const unsigned char * qdata,unsigned long qlen,const unsigned char * e1data,unsigned long e1len,const unsigned char * e2data,unsigned long e2len,const unsigned char * coeffdata,unsigned long coefflen)957 _libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa,
958 const unsigned char *edata,
959 unsigned long elen,
960 const unsigned char *ndata,
961 unsigned long nlen,
962 const unsigned char *ddata,
963 unsigned long dlen,
964 const unsigned char *pdata,
965 unsigned long plen,
966 const unsigned char *qdata,
967 unsigned long qlen,
968 const unsigned char *e1data,
969 unsigned long e1len,
970 const unsigned char *e2data,
971 unsigned long e2len,
972 const unsigned char *coeffdata,
973 unsigned long coefflen)
974 {
975 BCRYPT_KEY_HANDLE hKey;
976 BCRYPT_RSAKEY_BLOB *rsakey;
977 LPCWSTR lpszBlobType;
978 unsigned char *key;
979 unsigned long keylen, offset, mlen, p1len = 0, p2len = 0;
980 int ret;
981
982 mlen = max(_libssh2_wincng_bn_size(ndata, nlen),
983 _libssh2_wincng_bn_size(ddata, dlen));
984 offset = sizeof(BCRYPT_RSAKEY_BLOB);
985 keylen = offset + elen + mlen;
986 if(ddata && dlen > 0) {
987 p1len = max(_libssh2_wincng_bn_size(pdata, plen),
988 _libssh2_wincng_bn_size(e1data, e1len));
989 p2len = max(_libssh2_wincng_bn_size(qdata, qlen),
990 _libssh2_wincng_bn_size(e2data, e2len));
991 keylen += p1len * 3 + p2len * 2 + mlen;
992 }
993
994 key = malloc(keylen);
995 if(!key) {
996 return -1;
997 }
998
999 memset(key, 0, keylen);
1000
1001
1002 /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */
1003 rsakey = (BCRYPT_RSAKEY_BLOB *)key;
1004 rsakey->BitLength = mlen * 8;
1005 rsakey->cbPublicExp = elen;
1006 rsakey->cbModulus = mlen;
1007
1008 memcpy(key + offset, edata, elen);
1009 offset += elen;
1010
1011 if(nlen < mlen)
1012 memcpy(key + offset + mlen - nlen, ndata, nlen);
1013 else
1014 memcpy(key + offset, ndata + nlen - mlen, mlen);
1015
1016 if(ddata && dlen > 0) {
1017 offset += mlen;
1018
1019 if(plen < p1len)
1020 memcpy(key + offset + p1len - plen, pdata, plen);
1021 else
1022 memcpy(key + offset, pdata + plen - p1len, p1len);
1023 offset += p1len;
1024
1025 if(qlen < p2len)
1026 memcpy(key + offset + p2len - qlen, qdata, qlen);
1027 else
1028 memcpy(key + offset, qdata + qlen - p2len, p2len);
1029 offset += p2len;
1030
1031 if(e1len < p1len)
1032 memcpy(key + offset + p1len - e1len, e1data, e1len);
1033 else
1034 memcpy(key + offset, e1data + e1len - p1len, p1len);
1035 offset += p1len;
1036
1037 if(e2len < p2len)
1038 memcpy(key + offset + p2len - e2len, e2data, e2len);
1039 else
1040 memcpy(key + offset, e2data + e2len - p2len, p2len);
1041 offset += p2len;
1042
1043 if(coefflen < p1len)
1044 memcpy(key + offset + p1len - coefflen, coeffdata, coefflen);
1045 else
1046 memcpy(key + offset, coeffdata + coefflen - p1len, p1len);
1047 offset += p1len;
1048
1049 if(dlen < mlen)
1050 memcpy(key + offset + mlen - dlen, ddata, dlen);
1051 else
1052 memcpy(key + offset, ddata + dlen - mlen, mlen);
1053
1054 lpszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB;
1055 rsakey->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC;
1056 rsakey->cbPrime1 = p1len;
1057 rsakey->cbPrime2 = p2len;
1058 }
1059 else {
1060 lpszBlobType = BCRYPT_RSAPUBLIC_BLOB;
1061 rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC;
1062 rsakey->cbPrime1 = 0;
1063 rsakey->cbPrime2 = 0;
1064 }
1065
1066
1067 ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, lpszBlobType,
1068 &hKey, key, keylen, 0);
1069 if(!BCRYPT_SUCCESS(ret)) {
1070 _libssh2_wincng_safe_free(key, keylen);
1071 return -1;
1072 }
1073
1074
1075 *rsa = malloc(sizeof(libssh2_rsa_ctx));
1076 if(!(*rsa)) {
1077 BCryptDestroyKey(hKey);
1078 _libssh2_wincng_safe_free(key, keylen);
1079 return -1;
1080 }
1081
1082 (*rsa)->hKey = hKey;
1083 (*rsa)->pbKeyObject = key;
1084 (*rsa)->cbKeyObject = keylen;
1085
1086 return 0;
1087 }
1088
1089 #ifdef HAVE_LIBCRYPT32
1090 static int
_libssh2_wincng_rsa_new_private_parse(libssh2_rsa_ctx ** rsa,LIBSSH2_SESSION * session,unsigned char * pbEncoded,unsigned long cbEncoded)1091 _libssh2_wincng_rsa_new_private_parse(libssh2_rsa_ctx **rsa,
1092 LIBSSH2_SESSION *session,
1093 unsigned char *pbEncoded,
1094 unsigned long cbEncoded)
1095 {
1096 BCRYPT_KEY_HANDLE hKey;
1097 unsigned char *pbStructInfo;
1098 unsigned long cbStructInfo;
1099 int ret;
1100
1101 (void)session;
1102
1103 ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded,
1104 PKCS_RSA_PRIVATE_KEY,
1105 &pbStructInfo, &cbStructInfo);
1106
1107 _libssh2_wincng_safe_free(pbEncoded, cbEncoded);
1108
1109 if(ret) {
1110 return -1;
1111 }
1112
1113
1114 ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL,
1115 LEGACY_RSAPRIVATE_BLOB, &hKey,
1116 pbStructInfo, cbStructInfo, 0);
1117 if(!BCRYPT_SUCCESS(ret)) {
1118 _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo);
1119 return -1;
1120 }
1121
1122
1123 *rsa = malloc(sizeof(libssh2_rsa_ctx));
1124 if(!(*rsa)) {
1125 BCryptDestroyKey(hKey);
1126 _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo);
1127 return -1;
1128 }
1129
1130 (*rsa)->hKey = hKey;
1131 (*rsa)->pbKeyObject = pbStructInfo;
1132 (*rsa)->cbKeyObject = cbStructInfo;
1133
1134 return 0;
1135 }
1136 #endif /* HAVE_LIBCRYPT32 */
1137
1138 int
_libssh2_wincng_rsa_new_private(libssh2_rsa_ctx ** rsa,LIBSSH2_SESSION * session,const char * filename,const unsigned char * passphrase)1139 _libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa,
1140 LIBSSH2_SESSION *session,
1141 const char *filename,
1142 const unsigned char *passphrase)
1143 {
1144 #ifdef HAVE_LIBCRYPT32
1145 unsigned char *pbEncoded;
1146 unsigned long cbEncoded;
1147 int ret;
1148
1149 (void)session;
1150
1151 ret = _libssh2_wincng_load_private(session, filename,
1152 (const char *)passphrase,
1153 &pbEncoded, &cbEncoded, 1, 0);
1154 if(ret) {
1155 return -1;
1156 }
1157
1158 return _libssh2_wincng_rsa_new_private_parse(rsa, session,
1159 pbEncoded, cbEncoded);
1160 #else
1161 (void)rsa;
1162 (void)filename;
1163 (void)passphrase;
1164
1165 return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1166 "Unable to load RSA key from private key file: "
1167 "Method unsupported in Windows CNG backend");
1168 #endif /* HAVE_LIBCRYPT32 */
1169 }
1170
1171 int
_libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,LIBSSH2_SESSION * session,const char * filedata,size_t filedata_len,unsigned const char * passphrase)1172 _libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa,
1173 LIBSSH2_SESSION *session,
1174 const char *filedata,
1175 size_t filedata_len,
1176 unsigned const char *passphrase)
1177 {
1178 #ifdef HAVE_LIBCRYPT32
1179 unsigned char *pbEncoded;
1180 unsigned long cbEncoded;
1181 int ret;
1182
1183 (void)session;
1184
1185 ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len,
1186 (const char *)passphrase,
1187 &pbEncoded, &cbEncoded, 1, 0);
1188 if(ret) {
1189 return -1;
1190 }
1191
1192 return _libssh2_wincng_rsa_new_private_parse(rsa, session,
1193 pbEncoded, cbEncoded);
1194 #else
1195 (void)rsa;
1196 (void)filedata;
1197 (void)filedata_len;
1198 (void)passphrase;
1199
1200 return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
1201 "Unable to extract private key from memory: "
1202 "Method unsupported in Windows CNG backend");
1203 #endif /* HAVE_LIBCRYPT32 */
1204 }
1205
1206 int
_libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx * rsa,const unsigned char * sig,unsigned long sig_len,const unsigned char * m,unsigned long m_len)1207 _libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
1208 const unsigned char *sig,
1209 unsigned long sig_len,
1210 const unsigned char *m,
1211 unsigned long m_len)
1212 {
1213 return _libssh2_wincng_key_sha1_verify(rsa, sig, sig_len, m, m_len,
1214 BCRYPT_PAD_PKCS1);
1215 }
1216
1217 int
_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION * session,libssh2_rsa_ctx * rsa,const unsigned char * hash,size_t hash_len,unsigned char ** signature,size_t * signature_len)1218 _libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session,
1219 libssh2_rsa_ctx *rsa,
1220 const unsigned char *hash,
1221 size_t hash_len,
1222 unsigned char **signature,
1223 size_t *signature_len)
1224 {
1225 BCRYPT_PKCS1_PADDING_INFO paddingInfo;
1226 unsigned char *data, *sig;
1227 unsigned long cbData, datalen, siglen;
1228 int ret;
1229
1230 datalen = (unsigned long)hash_len;
1231 data = malloc(datalen);
1232 if(!data) {
1233 return -1;
1234 }
1235
1236 paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
1237
1238 memcpy(data, hash, datalen);
1239
1240 ret = BCryptSignHash(rsa->hKey, &paddingInfo,
1241 data, datalen, NULL, 0,
1242 &cbData, BCRYPT_PAD_PKCS1);
1243 if(BCRYPT_SUCCESS(ret)) {
1244 siglen = cbData;
1245 sig = LIBSSH2_ALLOC(session, siglen);
1246 if(sig) {
1247 ret = BCryptSignHash(rsa->hKey, &paddingInfo,
1248 data, datalen, sig, siglen,
1249 &cbData, BCRYPT_PAD_PKCS1);
1250 if(BCRYPT_SUCCESS(ret)) {
1251 *signature_len = siglen;
1252 *signature = sig;
1253 }
1254 else {
1255 LIBSSH2_FREE(session, sig);
1256 }
1257 }
1258 else
1259 ret = STATUS_NO_MEMORY;
1260 }
1261
1262 _libssh2_wincng_safe_free(data, datalen);
1263
1264 return BCRYPT_SUCCESS(ret) ? 0 : -1;
1265 }
1266
1267 void
_libssh2_wincng_rsa_free(libssh2_rsa_ctx * rsa)1268 _libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa)
1269 {
1270 if(!rsa)
1271 return;
1272
1273 BCryptDestroyKey(rsa->hKey);
1274 rsa->hKey = NULL;
1275
1276 _libssh2_wincng_safe_free(rsa->pbKeyObject, rsa->cbKeyObject);
1277 _libssh2_wincng_safe_free(rsa, sizeof(libssh2_rsa_ctx));
1278 }
1279
1280
1281 /*******************************************************************/
1282 /*
1283 * Windows CNG backend: DSA functions
1284 */
1285
1286 #if LIBSSH2_DSA
1287 int
_libssh2_wincng_dsa_new(libssh2_dsa_ctx ** dsa,const unsigned char * pdata,unsigned long plen,const unsigned char * qdata,unsigned long qlen,const unsigned char * gdata,unsigned long glen,const unsigned char * ydata,unsigned long ylen,const unsigned char * xdata,unsigned long xlen)1288 _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa,
1289 const unsigned char *pdata,
1290 unsigned long plen,
1291 const unsigned char *qdata,
1292 unsigned long qlen,
1293 const unsigned char *gdata,
1294 unsigned long glen,
1295 const unsigned char *ydata,
1296 unsigned long ylen,
1297 const unsigned char *xdata,
1298 unsigned long xlen)
1299 {
1300 BCRYPT_KEY_HANDLE hKey;
1301 BCRYPT_DSA_KEY_BLOB *dsakey;
1302 LPCWSTR lpszBlobType;
1303 unsigned char *key;
1304 unsigned long keylen, offset, length;
1305 int ret;
1306
1307 length = max(max(_libssh2_wincng_bn_size(pdata, plen),
1308 _libssh2_wincng_bn_size(gdata, glen)),
1309 _libssh2_wincng_bn_size(ydata, ylen));
1310 offset = sizeof(BCRYPT_DSA_KEY_BLOB);
1311 keylen = offset + length * 3;
1312 if(xdata && xlen > 0)
1313 keylen += 20;
1314
1315 key = malloc(keylen);
1316 if(!key) {
1317 return -1;
1318 }
1319
1320 memset(key, 0, keylen);
1321
1322
1323 /* https://msdn.microsoft.com/library/windows/desktop/aa833126.aspx */
1324 dsakey = (BCRYPT_DSA_KEY_BLOB *)key;
1325 dsakey->cbKey = length;
1326
1327 memset(dsakey->Count, -1, sizeof(dsakey->Count));
1328 memset(dsakey->Seed, -1, sizeof(dsakey->Seed));
1329
1330 if(qlen < 20)
1331 memcpy(dsakey->q + 20 - qlen, qdata, qlen);
1332 else
1333 memcpy(dsakey->q, qdata + qlen - 20, 20);
1334
1335 if(plen < length)
1336 memcpy(key + offset + length - plen, pdata, plen);
1337 else
1338 memcpy(key + offset, pdata + plen - length, length);
1339 offset += length;
1340
1341 if(glen < length)
1342 memcpy(key + offset + length - glen, gdata, glen);
1343 else
1344 memcpy(key + offset, gdata + glen - length, length);
1345 offset += length;
1346
1347 if(ylen < length)
1348 memcpy(key + offset + length - ylen, ydata, ylen);
1349 else
1350 memcpy(key + offset, ydata + ylen - length, length);
1351
1352 if(xdata && xlen > 0) {
1353 offset += length;
1354
1355 if(xlen < 20)
1356 memcpy(key + offset + 20 - xlen, xdata, xlen);
1357 else
1358 memcpy(key + offset, xdata + xlen - 20, 20);
1359
1360 lpszBlobType = BCRYPT_DSA_PRIVATE_BLOB;
1361 dsakey->dwMagic = BCRYPT_DSA_PRIVATE_MAGIC;
1362 }
1363 else {
1364 lpszBlobType = BCRYPT_DSA_PUBLIC_BLOB;
1365 dsakey->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC;
1366 }
1367
1368
1369 ret = BCryptImportKeyPair(_libssh2_wincng.hAlgDSA, NULL, lpszBlobType,
1370 &hKey, key, keylen, 0);
1371 if(!BCRYPT_SUCCESS(ret)) {
1372 _libssh2_wincng_safe_free(key, keylen);
1373 return -1;
1374 }
1375
1376
1377 *dsa = malloc(sizeof(libssh2_dsa_ctx));
1378 if(!(*dsa)) {
1379 BCryptDestroyKey(hKey);
1380 _libssh2_wincng_safe_free(key, keylen);
1381 return -1;
1382 }
1383
1384 (*dsa)->hKey = hKey;
1385 (*dsa)->pbKeyObject = key;
1386 (*dsa)->cbKeyObject = keylen;
1387
1388 return 0;
1389 }
1390
1391 #ifdef HAVE_LIBCRYPT32
1392 static int
_libssh2_wincng_dsa_new_private_parse(libssh2_dsa_ctx ** dsa,LIBSSH2_SESSION * session,unsigned char * pbEncoded,unsigned long cbEncoded)1393 _libssh2_wincng_dsa_new_private_parse(libssh2_dsa_ctx **dsa,
1394 LIBSSH2_SESSION *session,
1395 unsigned char *pbEncoded,
1396 unsigned long cbEncoded)
1397 {
1398 unsigned char **rpbDecoded;
1399 unsigned long *rcbDecoded, index, length;
1400 int ret;
1401
1402 (void)session;
1403
1404 ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded,
1405 &rpbDecoded, &rcbDecoded, &length);
1406
1407 _libssh2_wincng_safe_free(pbEncoded, cbEncoded);
1408
1409 if(ret) {
1410 return -1;
1411 }
1412
1413
1414 if(length == 6) {
1415 ret = _libssh2_wincng_dsa_new(dsa,
1416 rpbDecoded[1], rcbDecoded[1],
1417 rpbDecoded[2], rcbDecoded[2],
1418 rpbDecoded[3], rcbDecoded[3],
1419 rpbDecoded[4], rcbDecoded[4],
1420 rpbDecoded[5], rcbDecoded[5]);
1421 }
1422 else {
1423 ret = -1;
1424 }
1425
1426 for(index = 0; index < length; index++) {
1427 _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]);
1428 rpbDecoded[index] = NULL;
1429 rcbDecoded[index] = 0;
1430 }
1431
1432 free(rpbDecoded);
1433 free(rcbDecoded);
1434
1435 return ret;
1436 }
1437 #endif /* HAVE_LIBCRYPT32 */
1438
1439 int
_libssh2_wincng_dsa_new_private(libssh2_dsa_ctx ** dsa,LIBSSH2_SESSION * session,const char * filename,const unsigned char * passphrase)1440 _libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa,
1441 LIBSSH2_SESSION *session,
1442 const char *filename,
1443 const unsigned char *passphrase)
1444 {
1445 #ifdef HAVE_LIBCRYPT32
1446 unsigned char *pbEncoded;
1447 unsigned long cbEncoded;
1448 int ret;
1449
1450 ret = _libssh2_wincng_load_private(session, filename,
1451 (const char *)passphrase,
1452 &pbEncoded, &cbEncoded, 0, 1);
1453 if(ret) {
1454 return -1;
1455 }
1456
1457 return _libssh2_wincng_dsa_new_private_parse(dsa, session,
1458 pbEncoded, cbEncoded);
1459 #else
1460 (void)dsa;
1461 (void)filename;
1462 (void)passphrase;
1463
1464 return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1465 "Unable to load DSA key from private key file: "
1466 "Method unsupported in Windows CNG backend");
1467 #endif /* HAVE_LIBCRYPT32 */
1468 }
1469
1470 int
_libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,LIBSSH2_SESSION * session,const char * filedata,size_t filedata_len,unsigned const char * passphrase)1471 _libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa,
1472 LIBSSH2_SESSION *session,
1473 const char *filedata,
1474 size_t filedata_len,
1475 unsigned const char *passphrase)
1476 {
1477 #ifdef HAVE_LIBCRYPT32
1478 unsigned char *pbEncoded;
1479 unsigned long cbEncoded;
1480 int ret;
1481
1482 ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len,
1483 (const char *)passphrase,
1484 &pbEncoded, &cbEncoded, 0, 1);
1485 if(ret) {
1486 return -1;
1487 }
1488
1489 return _libssh2_wincng_dsa_new_private_parse(dsa, session,
1490 pbEncoded, cbEncoded);
1491 #else
1492 (void)dsa;
1493 (void)filedata;
1494 (void)filedata_len;
1495 (void)passphrase;
1496
1497 return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
1498 "Unable to extract private key from memory: "
1499 "Method unsupported in Windows CNG backend");
1500 #endif /* HAVE_LIBCRYPT32 */
1501 }
1502
1503 int
_libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx * dsa,const unsigned char * sig_fixed,const unsigned char * m,unsigned long m_len)1504 _libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa,
1505 const unsigned char *sig_fixed,
1506 const unsigned char *m,
1507 unsigned long m_len)
1508 {
1509 return _libssh2_wincng_key_sha1_verify(dsa, sig_fixed, 40, m, m_len, 0);
1510 }
1511
1512 int
_libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx * dsa,const unsigned char * hash,unsigned long hash_len,unsigned char * sig_fixed)1513 _libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa,
1514 const unsigned char *hash,
1515 unsigned long hash_len,
1516 unsigned char *sig_fixed)
1517 {
1518 unsigned char *data, *sig;
1519 unsigned long cbData, datalen, siglen;
1520 int ret;
1521
1522 datalen = hash_len;
1523 data = malloc(datalen);
1524 if(!data) {
1525 return -1;
1526 }
1527
1528 memcpy(data, hash, datalen);
1529
1530 ret = BCryptSignHash(dsa->hKey, NULL, data, datalen,
1531 NULL, 0, &cbData, 0);
1532 if(BCRYPT_SUCCESS(ret)) {
1533 siglen = cbData;
1534 if(siglen == 40) {
1535 sig = malloc(siglen);
1536 if(sig) {
1537 ret = BCryptSignHash(dsa->hKey, NULL, data, datalen,
1538 sig, siglen, &cbData, 0);
1539 if(BCRYPT_SUCCESS(ret)) {
1540 memcpy(sig_fixed, sig, siglen);
1541 }
1542
1543 _libssh2_wincng_safe_free(sig, siglen);
1544 }
1545 else
1546 ret = STATUS_NO_MEMORY;
1547 }
1548 else
1549 ret = STATUS_NO_MEMORY;
1550 }
1551
1552 _libssh2_wincng_safe_free(data, datalen);
1553
1554 return BCRYPT_SUCCESS(ret) ? 0 : -1;
1555 }
1556
1557 void
_libssh2_wincng_dsa_free(libssh2_dsa_ctx * dsa)1558 _libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa)
1559 {
1560 if(!dsa)
1561 return;
1562
1563 BCryptDestroyKey(dsa->hKey);
1564 dsa->hKey = NULL;
1565
1566 _libssh2_wincng_safe_free(dsa->pbKeyObject, dsa->cbKeyObject);
1567 _libssh2_wincng_safe_free(dsa, sizeof(libssh2_dsa_ctx));
1568 }
1569 #endif
1570
1571
1572 /*******************************************************************/
1573 /*
1574 * Windows CNG backend: Key functions
1575 */
1576
1577 #ifdef HAVE_LIBCRYPT32
1578 static unsigned long
_libssh2_wincng_pub_priv_write(unsigned char * key,unsigned long offset,const unsigned char * bignum,const unsigned long length)1579 _libssh2_wincng_pub_priv_write(unsigned char *key,
1580 unsigned long offset,
1581 const unsigned char *bignum,
1582 const unsigned long length)
1583 {
1584 _libssh2_htonu32(key + offset, length);
1585 offset += 4;
1586
1587 memcpy(key + offset, bignum, length);
1588 offset += length;
1589
1590 return offset;
1591 }
1592
1593 static int
_libssh2_wincng_pub_priv_keyfile_parse(LIBSSH2_SESSION * session,unsigned char ** method,size_t * method_len,unsigned char ** pubkeydata,size_t * pubkeydata_len,unsigned char * pbEncoded,unsigned long cbEncoded)1594 _libssh2_wincng_pub_priv_keyfile_parse(LIBSSH2_SESSION *session,
1595 unsigned char **method,
1596 size_t *method_len,
1597 unsigned char **pubkeydata,
1598 size_t *pubkeydata_len,
1599 unsigned char *pbEncoded,
1600 unsigned long cbEncoded)
1601 {
1602 unsigned char **rpbDecoded;
1603 unsigned long *rcbDecoded;
1604 unsigned char *key = NULL, *mth = NULL;
1605 unsigned long keylen = 0, mthlen = 0;
1606 unsigned long index, offset, length;
1607 int ret;
1608
1609 ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded,
1610 &rpbDecoded, &rcbDecoded, &length);
1611
1612 _libssh2_wincng_safe_free(pbEncoded, cbEncoded);
1613
1614 if(ret) {
1615 return -1;
1616 }
1617
1618
1619 if(length == 9) { /* private RSA key */
1620 mthlen = 7;
1621 mth = LIBSSH2_ALLOC(session, mthlen);
1622 if(mth) {
1623 memcpy(mth, "ssh-rsa", mthlen);
1624 }
1625 else {
1626 ret = -1;
1627 }
1628
1629
1630 keylen = 4 + mthlen + 4 + rcbDecoded[2] + 4 + rcbDecoded[1];
1631 key = LIBSSH2_ALLOC(session, keylen);
1632 if(key) {
1633 offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen);
1634
1635 offset = _libssh2_wincng_pub_priv_write(key, offset,
1636 rpbDecoded[2],
1637 rcbDecoded[2]);
1638
1639 _libssh2_wincng_pub_priv_write(key, offset,
1640 rpbDecoded[1],
1641 rcbDecoded[1]);
1642 }
1643 else {
1644 ret = -1;
1645 }
1646
1647 }
1648 else if(length == 6) { /* private DSA key */
1649 mthlen = 7;
1650 mth = LIBSSH2_ALLOC(session, mthlen);
1651 if(mth) {
1652 memcpy(mth, "ssh-dss", mthlen);
1653 }
1654 else {
1655 ret = -1;
1656 }
1657
1658 keylen = 4 + mthlen + 4 + rcbDecoded[1] + 4 + rcbDecoded[2]
1659 + 4 + rcbDecoded[3] + 4 + rcbDecoded[4];
1660 key = LIBSSH2_ALLOC(session, keylen);
1661 if(key) {
1662 offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen);
1663
1664 offset = _libssh2_wincng_pub_priv_write(key, offset,
1665 rpbDecoded[1],
1666 rcbDecoded[1]);
1667
1668 offset = _libssh2_wincng_pub_priv_write(key, offset,
1669 rpbDecoded[2],
1670 rcbDecoded[2]);
1671
1672 offset = _libssh2_wincng_pub_priv_write(key, offset,
1673 rpbDecoded[3],
1674 rcbDecoded[3]);
1675
1676 _libssh2_wincng_pub_priv_write(key, offset,
1677 rpbDecoded[4],
1678 rcbDecoded[4]);
1679 }
1680 else {
1681 ret = -1;
1682 }
1683
1684 }
1685 else {
1686 ret = -1;
1687 }
1688
1689
1690 for(index = 0; index < length; index++) {
1691 _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]);
1692 rpbDecoded[index] = NULL;
1693 rcbDecoded[index] = 0;
1694 }
1695
1696 free(rpbDecoded);
1697 free(rcbDecoded);
1698
1699
1700 if(ret) {
1701 if(mth)
1702 LIBSSH2_FREE(session, mth);
1703 if(key)
1704 LIBSSH2_FREE(session, key);
1705 }
1706 else {
1707 *method = mth;
1708 *method_len = mthlen;
1709 *pubkeydata = key;
1710 *pubkeydata_len = keylen;
1711 }
1712
1713 return ret;
1714 }
1715 #endif /* HAVE_LIBCRYPT32 */
1716
1717 int
_libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION * session,unsigned char ** method,size_t * method_len,unsigned char ** pubkeydata,size_t * pubkeydata_len,const char * privatekey,const char * passphrase)1718 _libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session,
1719 unsigned char **method,
1720 size_t *method_len,
1721 unsigned char **pubkeydata,
1722 size_t *pubkeydata_len,
1723 const char *privatekey,
1724 const char *passphrase)
1725 {
1726 #ifdef HAVE_LIBCRYPT32
1727 unsigned char *pbEncoded;
1728 unsigned long cbEncoded;
1729 int ret;
1730
1731 ret = _libssh2_wincng_load_private(session, privatekey, passphrase,
1732 &pbEncoded, &cbEncoded, 1, 1);
1733 if(ret) {
1734 return -1;
1735 }
1736
1737 return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len,
1738 pubkeydata, pubkeydata_len,
1739 pbEncoded, cbEncoded);
1740 #else
1741 (void)method;
1742 (void)method_len;
1743 (void)pubkeydata;
1744 (void)pubkeydata_len;
1745 (void)privatekey;
1746 (void)passphrase;
1747
1748 return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1749 "Unable to load public key from private key file: "
1750 "Method unsupported in Windows CNG backend");
1751 #endif /* HAVE_LIBCRYPT32 */
1752 }
1753
1754 int
_libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION * session,unsigned char ** method,size_t * method_len,unsigned char ** pubkeydata,size_t * pubkeydata_len,const char * privatekeydata,size_t privatekeydata_len,const char * passphrase)1755 _libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
1756 unsigned char **method,
1757 size_t *method_len,
1758 unsigned char **pubkeydata,
1759 size_t *pubkeydata_len,
1760 const char *privatekeydata,
1761 size_t privatekeydata_len,
1762 const char *passphrase)
1763 {
1764 #ifdef HAVE_LIBCRYPT32
1765 unsigned char *pbEncoded;
1766 unsigned long cbEncoded;
1767 int ret;
1768
1769 ret = _libssh2_wincng_load_private_memory(session, privatekeydata,
1770 privatekeydata_len, passphrase,
1771 &pbEncoded, &cbEncoded, 1, 1);
1772 if(ret) {
1773 return -1;
1774 }
1775
1776 return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len,
1777 pubkeydata, pubkeydata_len,
1778 pbEncoded, cbEncoded);
1779 #else
1780 (void)method;
1781 (void)method_len;
1782 (void)pubkeydata_len;
1783 (void)pubkeydata;
1784 (void)privatekeydata;
1785 (void)privatekeydata_len;
1786 (void)passphrase;
1787
1788 return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
1789 "Unable to extract public key from private key in memory: "
1790 "Method unsupported in Windows CNG backend");
1791 #endif /* HAVE_LIBCRYPT32 */
1792 }
1793
1794 /*******************************************************************/
1795 /*
1796 * Windows CNG backend: Cipher functions
1797 */
1798
1799 int
_libssh2_wincng_cipher_init(_libssh2_cipher_ctx * ctx,_libssh2_cipher_type (type),unsigned char * iv,unsigned char * secret,int encrypt)1800 _libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx,
1801 _libssh2_cipher_type(type),
1802 unsigned char *iv,
1803 unsigned char *secret,
1804 int encrypt)
1805 {
1806 BCRYPT_KEY_HANDLE hKey;
1807 BCRYPT_KEY_DATA_BLOB_HEADER *header;
1808 unsigned char *pbKeyObject, *pbIV, *key, *pbCtr, *pbIVCopy;
1809 unsigned long dwKeyObject, dwIV, dwCtrLength, dwBlockLength,
1810 cbData, keylen;
1811 int ret;
1812
1813 (void)encrypt;
1814
1815 ret = BCryptGetProperty(*type.phAlg, BCRYPT_OBJECT_LENGTH,
1816 (unsigned char *)&dwKeyObject,
1817 sizeof(dwKeyObject),
1818 &cbData, 0);
1819 if(!BCRYPT_SUCCESS(ret)) {
1820 return -1;
1821 }
1822
1823 ret = BCryptGetProperty(*type.phAlg, BCRYPT_BLOCK_LENGTH,
1824 (unsigned char *)&dwBlockLength,
1825 sizeof(dwBlockLength),
1826 &cbData, 0);
1827 if(!BCRYPT_SUCCESS(ret)) {
1828 return -1;
1829 }
1830
1831 pbKeyObject = malloc(dwKeyObject);
1832 if(!pbKeyObject) {
1833 return -1;
1834 }
1835
1836
1837 keylen = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + type.dwKeyLength;
1838 key = malloc(keylen);
1839 if(!key) {
1840 free(pbKeyObject);
1841 return -1;
1842 }
1843
1844
1845 header = (BCRYPT_KEY_DATA_BLOB_HEADER *)key;
1846 header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
1847 header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
1848 header->cbKeyData = type.dwKeyLength;
1849
1850 memcpy(key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER),
1851 secret, type.dwKeyLength);
1852
1853 ret = BCryptImportKey(*type.phAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey,
1854 pbKeyObject, dwKeyObject, key, keylen, 0);
1855
1856 _libssh2_wincng_safe_free(key, keylen);
1857
1858 if(!BCRYPT_SUCCESS(ret)) {
1859 _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject);
1860 return -1;
1861 }
1862
1863 pbIV = NULL;
1864 pbCtr = NULL;
1865 dwIV = 0;
1866 dwCtrLength = 0;
1867
1868 if(type.useIV || type.ctrMode) {
1869 pbIVCopy = malloc(dwBlockLength);
1870 if(!pbIVCopy) {
1871 BCryptDestroyKey(hKey);
1872 _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject);
1873 return -1;
1874 }
1875 memcpy(pbIVCopy, iv, dwBlockLength);
1876
1877 if(type.ctrMode) {
1878 pbCtr = pbIVCopy;
1879 dwCtrLength = dwBlockLength;
1880 }
1881 else if(type.useIV) {
1882 pbIV = pbIVCopy;
1883 dwIV = dwBlockLength;
1884 }
1885 }
1886
1887 ctx->hKey = hKey;
1888 ctx->pbKeyObject = pbKeyObject;
1889 ctx->pbIV = pbIV;
1890 ctx->pbCtr = pbCtr;
1891 ctx->dwKeyObject = dwKeyObject;
1892 ctx->dwIV = dwIV;
1893 ctx->dwBlockLength = dwBlockLength;
1894 ctx->dwCtrLength = dwCtrLength;
1895
1896 return 0;
1897 }
1898 int
_libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx * ctx,_libssh2_cipher_type (type),int encrypt,unsigned char * block,size_t blocklen)1899 _libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx,
1900 _libssh2_cipher_type(type),
1901 int encrypt,
1902 unsigned char *block,
1903 size_t blocklen)
1904 {
1905 unsigned char *pbOutput, *pbInput;
1906 unsigned long cbOutput, cbInput;
1907 int ret;
1908
1909 (void)type;
1910
1911 cbInput = (unsigned long)blocklen;
1912
1913 if(type.ctrMode) {
1914 pbInput = ctx->pbCtr;
1915 }
1916 else {
1917 pbInput = block;
1918 }
1919
1920 if(encrypt || type.ctrMode) {
1921 ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL,
1922 ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0);
1923 }
1924 else {
1925 ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL,
1926 ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0);
1927 }
1928 if(BCRYPT_SUCCESS(ret)) {
1929 pbOutput = malloc(cbOutput);
1930 if(pbOutput) {
1931 if(encrypt || type.ctrMode) {
1932 ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL,
1933 ctx->pbIV, ctx->dwIV,
1934 pbOutput, cbOutput, &cbOutput, 0);
1935 }
1936 else {
1937 ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL,
1938 ctx->pbIV, ctx->dwIV,
1939 pbOutput, cbOutput, &cbOutput, 0);
1940 }
1941 if(BCRYPT_SUCCESS(ret)) {
1942 if(type.ctrMode) {
1943 _libssh2_xor_data(block, block, pbOutput, blocklen);
1944 _libssh2_aes_ctr_increment(ctx->pbCtr, ctx->dwCtrLength);
1945 }
1946 else {
1947 memcpy(block, pbOutput, cbOutput);
1948 }
1949 }
1950
1951 _libssh2_wincng_safe_free(pbOutput, cbOutput);
1952 }
1953 else
1954 ret = STATUS_NO_MEMORY;
1955 }
1956
1957 return BCRYPT_SUCCESS(ret) ? 0 : -1;
1958 }
1959
1960 void
_libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx * ctx)1961 _libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx)
1962 {
1963 BCryptDestroyKey(ctx->hKey);
1964 ctx->hKey = NULL;
1965
1966 _libssh2_wincng_safe_free(ctx->pbKeyObject, ctx->dwKeyObject);
1967 ctx->pbKeyObject = NULL;
1968 ctx->dwKeyObject = 0;
1969
1970 _libssh2_wincng_safe_free(ctx->pbIV, ctx->dwBlockLength);
1971 ctx->pbIV = NULL;
1972 ctx->dwBlockLength = 0;
1973
1974 _libssh2_wincng_safe_free(ctx->pbCtr, ctx->dwCtrLength);
1975 ctx->pbCtr = NULL;
1976 ctx->dwCtrLength = 0;
1977 }
1978
1979
1980 /*******************************************************************/
1981 /*
1982 * Windows CNG backend: BigNumber functions
1983 */
1984
1985 _libssh2_bn *
_libssh2_wincng_bignum_init(void)1986 _libssh2_wincng_bignum_init(void)
1987 {
1988 _libssh2_bn *bignum;
1989
1990 bignum = (_libssh2_bn *)malloc(sizeof(_libssh2_bn));
1991 if(bignum) {
1992 bignum->bignum = NULL;
1993 bignum->length = 0;
1994 }
1995
1996 return bignum;
1997 }
1998
1999 static int
_libssh2_wincng_bignum_resize(_libssh2_bn * bn,unsigned long length)2000 _libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length)
2001 {
2002 unsigned char *bignum;
2003
2004 if(!bn)
2005 return -1;
2006
2007 if(length == bn->length)
2008 return 0;
2009
2010 #ifdef LIBSSH2_CLEAR_MEMORY
2011 if(bn->bignum && bn->length > 0 && length < bn->length) {
2012 SecureZeroMemory(bn->bignum + length, bn->length - length);
2013 }
2014 #endif
2015
2016 bignum = realloc(bn->bignum, length);
2017 if(!bignum)
2018 return -1;
2019
2020 bn->bignum = bignum;
2021 bn->length = length;
2022
2023 return 0;
2024 }
2025
2026 static int
_libssh2_wincng_bignum_rand(_libssh2_bn * rnd,int bits,int top,int bottom)2027 _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom)
2028 {
2029 unsigned char *bignum;
2030 unsigned long length;
2031
2032 if(!rnd)
2033 return -1;
2034
2035 length = (unsigned long) (ceil(((double)bits) / 8.0) *
2036 sizeof(unsigned char));
2037 if(_libssh2_wincng_bignum_resize(rnd, length))
2038 return -1;
2039
2040 bignum = rnd->bignum;
2041
2042 if(_libssh2_wincng_random(bignum, length))
2043 return -1;
2044
2045 /* calculate significant bits in most significant byte */
2046 bits %= 8;
2047 if(bits == 0)
2048 bits = 8;
2049
2050 /* fill most significant byte with zero padding */
2051 bignum[0] &= ((1 << bits) - 1);
2052
2053 /* set most significant bits in most significant byte */
2054 if(top == 0)
2055 bignum[0] |= (1 << (bits - 1));
2056 else if(top == 1)
2057 bignum[0] |= (3 << (bits - 2));
2058
2059 /* make odd by setting first bit in least significant byte */
2060 if(bottom)
2061 bignum[length - 1] |= 1;
2062
2063 return 0;
2064 }
2065
2066 static int
_libssh2_wincng_bignum_mod_exp(_libssh2_bn * r,_libssh2_bn * a,_libssh2_bn * p,_libssh2_bn * m)2067 _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r,
2068 _libssh2_bn *a,
2069 _libssh2_bn *p,
2070 _libssh2_bn *m)
2071 {
2072 BCRYPT_KEY_HANDLE hKey;
2073 BCRYPT_RSAKEY_BLOB *rsakey;
2074 unsigned char *key, *bignum;
2075 unsigned long keylen, offset, length;
2076 int ret;
2077
2078 if(!r || !a || !p || !m)
2079 return -1;
2080
2081 offset = sizeof(BCRYPT_RSAKEY_BLOB);
2082 keylen = offset + p->length + m->length;
2083
2084 key = malloc(keylen);
2085 if(!key)
2086 return -1;
2087
2088
2089 /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */
2090 rsakey = (BCRYPT_RSAKEY_BLOB *)key;
2091 rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC;
2092 rsakey->BitLength = m->length * 8;
2093 rsakey->cbPublicExp = p->length;
2094 rsakey->cbModulus = m->length;
2095 rsakey->cbPrime1 = 0;
2096 rsakey->cbPrime2 = 0;
2097
2098 memcpy(key + offset, p->bignum, p->length);
2099 offset += p->length;
2100
2101 memcpy(key + offset, m->bignum, m->length);
2102 offset = 0;
2103
2104 ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL,
2105 BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, 0);
2106 if(BCRYPT_SUCCESS(ret)) {
2107 ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0,
2108 NULL, 0, &length, BCRYPT_PAD_NONE);
2109 if(BCRYPT_SUCCESS(ret)) {
2110 if(!_libssh2_wincng_bignum_resize(r, length)) {
2111 length = max(a->length, length);
2112 bignum = malloc(length);
2113 if(bignum) {
2114 memcpy_with_be_padding(bignum, length,
2115 a->bignum, a->length);
2116
2117 ret = BCryptEncrypt(hKey, bignum, length, NULL, NULL, 0,
2118 r->bignum, r->length, &offset,
2119 BCRYPT_PAD_NONE);
2120
2121 _libssh2_wincng_safe_free(bignum, length);
2122
2123 if(BCRYPT_SUCCESS(ret)) {
2124 _libssh2_wincng_bignum_resize(r, offset);
2125 }
2126 }
2127 else
2128 ret = STATUS_NO_MEMORY;
2129 }
2130 else
2131 ret = STATUS_NO_MEMORY;
2132 }
2133
2134 BCryptDestroyKey(hKey);
2135 }
2136
2137 _libssh2_wincng_safe_free(key, keylen);
2138
2139 return BCRYPT_SUCCESS(ret) ? 0 : -1;
2140 }
2141
2142 int
_libssh2_wincng_bignum_set_word(_libssh2_bn * bn,unsigned long word)2143 _libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word)
2144 {
2145 unsigned long offset, number, bits, length;
2146
2147 if(!bn)
2148 return -1;
2149
2150 bits = 0;
2151 number = word;
2152 while(number >>= 1)
2153 bits++;
2154 bits++;
2155
2156 length = (unsigned long) (ceil(((double)bits) / 8.0) *
2157 sizeof(unsigned char));
2158 if(_libssh2_wincng_bignum_resize(bn, length))
2159 return -1;
2160
2161 for(offset = 0; offset < length; offset++)
2162 bn->bignum[offset] = (word >> (offset * 8)) & 0xff;
2163
2164 return 0;
2165 }
2166
2167 unsigned long
_libssh2_wincng_bignum_bits(const _libssh2_bn * bn)2168 _libssh2_wincng_bignum_bits(const _libssh2_bn *bn)
2169 {
2170 unsigned char number;
2171 unsigned long offset, length, bits;
2172
2173 if(!bn || !bn->bignum || !bn->length)
2174 return 0;
2175
2176 offset = 0;
2177 length = bn->length - 1;
2178 while(!bn->bignum[offset] && offset < length)
2179 offset++;
2180
2181 bits = (length - offset) * 8;
2182 number = bn->bignum[offset];
2183 while(number >>= 1)
2184 bits++;
2185 bits++;
2186
2187 return bits;
2188 }
2189
2190 void
_libssh2_wincng_bignum_from_bin(_libssh2_bn * bn,unsigned long len,const unsigned char * bin)2191 _libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len,
2192 const unsigned char *bin)
2193 {
2194 unsigned char *bignum;
2195 unsigned long offset, length, bits;
2196
2197 if(!bn || !bin || !len)
2198 return;
2199
2200 if(_libssh2_wincng_bignum_resize(bn, len))
2201 return;
2202
2203 memcpy(bn->bignum, bin, len);
2204
2205 bits = _libssh2_wincng_bignum_bits(bn);
2206 length = (unsigned long) (ceil(((double)bits) / 8.0) *
2207 sizeof(unsigned char));
2208
2209 offset = bn->length - length;
2210 if(offset > 0) {
2211 memmove(bn->bignum, bn->bignum + offset, length);
2212
2213 #ifdef LIBSSH2_CLEAR_MEMORY
2214 SecureZeroMemory(bn->bignum + length, offset);
2215 #endif
2216
2217 bignum = realloc(bn->bignum, length);
2218 if(bignum) {
2219 bn->bignum = bignum;
2220 bn->length = length;
2221 }
2222 }
2223 }
2224
2225 void
_libssh2_wincng_bignum_to_bin(const _libssh2_bn * bn,unsigned char * bin)2226 _libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin)
2227 {
2228 if(bin && bn && bn->bignum && bn->length > 0) {
2229 memcpy(bin, bn->bignum, bn->length);
2230 }
2231 }
2232
2233 void
_libssh2_wincng_bignum_free(_libssh2_bn * bn)2234 _libssh2_wincng_bignum_free(_libssh2_bn *bn)
2235 {
2236 if(bn) {
2237 if(bn->bignum) {
2238 _libssh2_wincng_safe_free(bn->bignum, bn->length);
2239 bn->bignum = NULL;
2240 }
2241 bn->length = 0;
2242 _libssh2_wincng_safe_free(bn, sizeof(_libssh2_bn));
2243 }
2244 }
2245
2246
2247 /*******************************************************************/
2248 /*
2249 * Windows CNG backend: Diffie-Hellman support.
2250 */
2251
2252 void
_libssh2_dh_init(_libssh2_dh_ctx * dhctx)2253 _libssh2_dh_init(_libssh2_dh_ctx *dhctx)
2254 {
2255 /* Random from client */
2256 dhctx->bn = NULL;
2257 dhctx->dh_handle = NULL;
2258 dhctx->dh_params = NULL;
2259 }
2260
2261 void
_libssh2_dh_dtor(_libssh2_dh_ctx * dhctx)2262 _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
2263 {
2264 if(dhctx->dh_handle) {
2265 BCryptDestroyKey(dhctx->dh_handle);
2266 dhctx->dh_handle = NULL;
2267 }
2268 if(dhctx->dh_params) {
2269 /* Since public dh_params are shared in clear text,
2270 * we don't need to securely zero them out here */
2271 free(dhctx->dh_params);
2272 dhctx->dh_params = NULL;
2273 }
2274 if(dhctx->bn) {
2275 _libssh2_wincng_bignum_free(dhctx->bn);
2276 dhctx->bn = NULL;
2277 }
2278 }
2279
2280 /* Generates a Diffie-Hellman key pair using base `g', prime `p' and the given
2281 * `group_order'. Can use the given big number context `bnctx' if needed. The
2282 * private key is stored as opaque in the Diffie-Hellman context `*dhctx' and
2283 * the public key is returned in `public'. 0 is returned upon success, else
2284 * -1. */
2285 int
_libssh2_dh_key_pair(_libssh2_dh_ctx * dhctx,_libssh2_bn * public,_libssh2_bn * g,_libssh2_bn * p,int group_order)2286 _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
2287 _libssh2_bn *g, _libssh2_bn *p, int group_order)
2288 {
2289 const int hasAlgDHwithKDF = _libssh2_wincng.hasAlgDHwithKDF;
2290 while(_libssh2_wincng.hAlgDH && hasAlgDHwithKDF != -1) {
2291 BCRYPT_DH_PARAMETER_HEADER *dh_params = NULL;
2292 unsigned long dh_params_len;
2293 unsigned char *blob = NULL;
2294 int status;
2295 /* Note that the DH provider requires that keys be multiples of 64 bits
2296 * in length. At the time of writing a practical observed group_order
2297 * value is 257, so we need to round down to 8 bytes of length (64/8)
2298 * in order for kex to succeed */
2299 DWORD key_length_bytes = max(round_down(group_order, 8),
2300 max(g->length, p->length));
2301 BCRYPT_DH_KEY_BLOB *dh_key_blob;
2302 LPCWSTR key_type;
2303
2304 /* Prepare a key pair; pass the in the bit length of the key,
2305 * but the key is not ready for consumption until it is finalized. */
2306 status = BCryptGenerateKeyPair(_libssh2_wincng.hAlgDH,
2307 &dhctx->dh_handle,
2308 key_length_bytes * 8, 0);
2309 if(!BCRYPT_SUCCESS(status)) {
2310 return -1;
2311 }
2312
2313 dh_params_len = sizeof(*dh_params) + 2 * key_length_bytes;
2314 blob = malloc(dh_params_len);
2315 if(!blob) {
2316 return -1;
2317 }
2318
2319 /* Populate DH parameters blob; after the header follows the `p`
2320 * value and the `g` value. */
2321 dh_params = (BCRYPT_DH_PARAMETER_HEADER*)blob;
2322 dh_params->cbLength = dh_params_len;
2323 dh_params->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC;
2324 dh_params->cbKeyLength = key_length_bytes;
2325 memcpy_with_be_padding(blob + sizeof(*dh_params), key_length_bytes,
2326 p->bignum, p->length);
2327 memcpy_with_be_padding(blob + sizeof(*dh_params) + key_length_bytes,
2328 key_length_bytes, g->bignum, g->length);
2329
2330 status = BCryptSetProperty(dhctx->dh_handle, BCRYPT_DH_PARAMETERS,
2331 blob, dh_params_len, 0);
2332 if(hasAlgDHwithKDF == -1) {
2333 /* We know that the raw KDF is not supported, so discard this. */
2334 free(blob);
2335 }
2336 else {
2337 /* Pass ownership to dhctx; these parameters will be freed when
2338 * the context is destroyed. We need to keep the parameters more
2339 * easily available so that we have access to the `g` value when
2340 * _libssh2_dh_secret is called later. */
2341 dhctx->dh_params = dh_params;
2342 }
2343 dh_params = NULL;
2344 blob = NULL;
2345
2346 if(!BCRYPT_SUCCESS(status)) {
2347 return -1;
2348 }
2349
2350 status = BCryptFinalizeKeyPair(dhctx->dh_handle, 0);
2351 if(!BCRYPT_SUCCESS(status)) {
2352 return -1;
2353 }
2354
2355 key_length_bytes = 0;
2356 if(hasAlgDHwithKDF == 1) {
2357 /* Now we need to extract the public portion of the key so that we
2358 * set it in the `public` bignum to satisfy our caller.
2359 * First measure up the size of the required buffer. */
2360 key_type = BCRYPT_DH_PUBLIC_BLOB;
2361 }
2362 else {
2363 /* We also need to extract the private portion of the key to
2364 * set it in the `*dhctx' bignum if the raw KDF is not supported.
2365 * First measure up the size of the required buffer. */
2366 key_type = BCRYPT_DH_PRIVATE_BLOB;
2367 }
2368 status = BCryptExportKey(dhctx->dh_handle, NULL, key_type,
2369 NULL, 0, &key_length_bytes, 0);
2370 if(!BCRYPT_SUCCESS(status)) {
2371 return -1;
2372 }
2373
2374 blob = malloc(key_length_bytes);
2375 if(!blob) {
2376 return -1;
2377 }
2378
2379 status = BCryptExportKey(dhctx->dh_handle, NULL, key_type,
2380 blob, key_length_bytes,
2381 &key_length_bytes, 0);
2382 if(!BCRYPT_SUCCESS(status)) {
2383 if(hasAlgDHwithKDF == 1) {
2384 /* We have no private data, because raw KDF is supported */
2385 free(blob);
2386 }
2387 else { /* we may have potentially private data, use secure free */
2388 _libssh2_wincng_safe_free(blob, key_length_bytes);
2389 }
2390 return -1;
2391 }
2392
2393 if(hasAlgDHwithKDF == -1) {
2394 /* We know that the raw KDF is not supported, so discard this */
2395 BCryptDestroyKey(dhctx->dh_handle);
2396 dhctx->dh_handle = NULL;
2397 }
2398
2399 /* BCRYPT_DH_PUBLIC_BLOB corresponds to a BCRYPT_DH_KEY_BLOB header
2400 * followed by the Modulus, Generator and Public data. Those components
2401 * each have equal size, specified by dh_key_blob->cbKey. */
2402 dh_key_blob = (BCRYPT_DH_KEY_BLOB*)blob;
2403 if(_libssh2_wincng_bignum_resize(public, dh_key_blob->cbKey)) {
2404 if(hasAlgDHwithKDF == 1) {
2405 /* We have no private data, because raw KDF is supported */
2406 free(blob);
2407 }
2408 else { /* we may have potentially private data, use secure free */
2409 _libssh2_wincng_safe_free(blob, key_length_bytes);
2410 }
2411 return -1;
2412 }
2413
2414 /* Copy the public key data into the public bignum data buffer */
2415 memcpy(public->bignum,
2416 blob + sizeof(*dh_key_blob) + 2 * dh_key_blob->cbKey,
2417 dh_key_blob->cbKey);
2418
2419 if(dh_key_blob->dwMagic == BCRYPT_DH_PRIVATE_MAGIC) {
2420 /* BCRYPT_DH_PRIVATE_BLOB additionally contains the Private data */
2421 dhctx->bn = _libssh2_wincng_bignum_init();
2422 if(!dhctx->bn) {
2423 _libssh2_wincng_safe_free(blob, key_length_bytes);
2424 return -1;
2425 }
2426 if(_libssh2_wincng_bignum_resize(dhctx->bn, dh_key_blob->cbKey)) {
2427 _libssh2_wincng_safe_free(blob, key_length_bytes);
2428 return -1;
2429 }
2430
2431 /* Copy the private key data into the dhctx bignum data buffer */
2432 memcpy(dhctx->bn->bignum,
2433 blob + sizeof(*dh_key_blob) + 3 * dh_key_blob->cbKey,
2434 dh_key_blob->cbKey);
2435
2436 /* Make sure the private key is an odd number, because only
2437 * odd primes can be used with the RSA-based fallback while
2438 * DH itself does not seem to care about it being odd or not. */
2439 if(!(dhctx->bn->bignum[dhctx->bn->length-1] % 2)) {
2440 _libssh2_wincng_safe_free(blob, key_length_bytes);
2441 /* discard everything first, then try again */
2442 _libssh2_dh_dtor(dhctx);
2443 _libssh2_dh_init(dhctx);
2444 continue;
2445 }
2446 }
2447
2448 return 0;
2449 }
2450
2451 /* Generate x and e */
2452 dhctx->bn = _libssh2_wincng_bignum_init();
2453 if(!dhctx->bn)
2454 return -1;
2455 if(_libssh2_wincng_bignum_rand(dhctx->bn, group_order * 8 - 1, 0, -1))
2456 return -1;
2457 if(_libssh2_wincng_bignum_mod_exp(public, g, dhctx->bn, p))
2458 return -1;
2459
2460 return 0;
2461 }
2462
2463 /* Computes the Diffie-Hellman secret from the previously created context
2464 * `*dhctx', the public key `f' from the other party and the same prime `p'
2465 * used at context creation. The result is stored in `secret'. 0 is returned
2466 * upon success, else -1. */
2467 int
_libssh2_dh_secret(_libssh2_dh_ctx * dhctx,_libssh2_bn * secret,_libssh2_bn * f,_libssh2_bn * p)2468 _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
2469 _libssh2_bn *f, _libssh2_bn *p)
2470 {
2471 if(_libssh2_wincng.hAlgDH && _libssh2_wincng.hasAlgDHwithKDF != -1 &&
2472 dhctx->dh_handle && dhctx->dh_params && f) {
2473 BCRYPT_KEY_HANDLE peer_public = NULL;
2474 BCRYPT_SECRET_HANDLE agreement = NULL;
2475 ULONG secret_len_bytes = 0;
2476 unsigned char *blob;
2477 int status;
2478 unsigned char *start, *end;
2479 BCRYPT_DH_KEY_BLOB *public_blob = NULL;
2480 DWORD key_length_bytes = max(f->length, dhctx->dh_params->cbKeyLength);
2481 DWORD public_blob_len = sizeof(*public_blob) + 3 * key_length_bytes;
2482
2483 {
2484 /* Populate a BCRYPT_DH_KEY_BLOB; after the header follows the
2485 * Modulus, Generator and Public data. Those components must have
2486 * equal size in this representation. */
2487 unsigned char *dest;
2488 unsigned char *src;
2489
2490 blob = malloc(public_blob_len);
2491 if(!blob) {
2492 return -1;
2493 }
2494 public_blob = (BCRYPT_DH_KEY_BLOB*)blob;
2495 public_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC;
2496 public_blob->cbKey = key_length_bytes;
2497
2498 dest = (unsigned char *)(public_blob + 1);
2499 src = (unsigned char *)(dhctx->dh_params + 1);
2500
2501 /* Modulus (the p-value from the first call) */
2502 memcpy_with_be_padding(dest, key_length_bytes, src,
2503 dhctx->dh_params->cbKeyLength);
2504 /* Generator (the g-value from the first call) */
2505 memcpy_with_be_padding(dest + key_length_bytes, key_length_bytes,
2506 src + dhctx->dh_params->cbKeyLength,
2507 dhctx->dh_params->cbKeyLength);
2508 /* Public from the peer */
2509 memcpy_with_be_padding(dest + 2*key_length_bytes, key_length_bytes,
2510 f->bignum, f->length);
2511 }
2512
2513 /* Import the peer public key information */
2514 status = BCryptImportKeyPair(_libssh2_wincng.hAlgDH, NULL,
2515 BCRYPT_DH_PUBLIC_BLOB, &peer_public, blob,
2516 public_blob_len, 0);
2517 if(!BCRYPT_SUCCESS(status)) {
2518 goto out;
2519 }
2520
2521 /* Set up a handle that we can use to establish the shared secret
2522 * between ourselves (our saved dh_handle) and the peer. */
2523 status = BCryptSecretAgreement(dhctx->dh_handle, peer_public,
2524 &agreement, 0);
2525 if(!BCRYPT_SUCCESS(status)) {
2526 goto out;
2527 }
2528
2529 /* Compute the size of the buffer that is needed to hold the derived
2530 * shared secret. */
2531 status = BCryptDeriveKey(agreement, BCRYPT_KDF_RAW_SECRET, NULL, NULL,
2532 0, &secret_len_bytes, 0);
2533 if(!BCRYPT_SUCCESS(status)) {
2534 if(status == STATUS_NOT_SUPPORTED) {
2535 _libssh2_wincng.hasAlgDHwithKDF = -1;
2536 }
2537 goto out;
2538 }
2539
2540 /* Expand the secret bignum to be ready to receive the derived secret
2541 * */
2542 if(_libssh2_wincng_bignum_resize(secret, secret_len_bytes)) {
2543 status = STATUS_NO_MEMORY;
2544 goto out;
2545 }
2546
2547 /* And populate the secret bignum */
2548 status = BCryptDeriveKey(agreement, BCRYPT_KDF_RAW_SECRET, NULL,
2549 secret->bignum, secret_len_bytes,
2550 &secret_len_bytes, 0);
2551 if(!BCRYPT_SUCCESS(status)) {
2552 if(status == STATUS_NOT_SUPPORTED) {
2553 _libssh2_wincng.hasAlgDHwithKDF = -1;
2554 }
2555 goto out;
2556 }
2557
2558 /* Counter to all the other data in the BCrypt APIs, the raw secret is
2559 * returned to us in host byte order, so we need to swap it to big
2560 * endian order. */
2561 start = secret->bignum;
2562 end = secret->bignum + secret->length - 1;
2563 while(start < end) {
2564 unsigned char tmp = *end;
2565 *end = *start;
2566 *start = tmp;
2567 start++;
2568 end--;
2569 }
2570
2571 status = 0;
2572 _libssh2_wincng.hasAlgDHwithKDF = 1;
2573
2574 out:
2575 if(peer_public) {
2576 BCryptDestroyKey(peer_public);
2577 }
2578 if(agreement) {
2579 BCryptDestroySecret(agreement);
2580 }
2581 if(status == STATUS_NOT_SUPPORTED &&
2582 _libssh2_wincng.hasAlgDHwithKDF == -1) {
2583 goto fb; /* fallback to RSA-based implementation */
2584 }
2585 return BCRYPT_SUCCESS(status) ? 0 : -1;
2586 }
2587
2588 fb:
2589 /* Compute the shared secret */
2590 return _libssh2_wincng_bignum_mod_exp(secret, f, dhctx->bn, p);
2591 }
2592
2593 #endif /* LIBSSH2_WINCNG */
2594