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