1 /*
2  * Copyright (C) 2013-2015 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 <math.h>
62 #include "misc.h"
63 
64 #ifdef HAVE_STDLIB_H
65 #include <stdlib.h>
66 #endif
67 #ifdef HAVE_LIBCRYPT32
68 #include <wincrypt.h>
69 #endif
70 
71 #define PEM_RSA_HEADER "-----BEGIN RSA PRIVATE KEY-----"
72 #define PEM_RSA_FOOTER "-----END RSA PRIVATE KEY-----"
73 #define PEM_DSA_HEADER "-----BEGIN DSA PRIVATE KEY-----"
74 #define PEM_DSA_FOOTER "-----END DSA PRIVATE KEY-----"
75 
76 
77 /*******************************************************************/
78 /*
79  * Windows CNG backend: Missing definitions (for MinGW[-w64])
80  */
81 #ifndef BCRYPT_SUCCESS
82 #define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
83 #endif
84 
85 #ifndef BCRYPT_RNG_ALGORITHM
86 #define BCRYPT_RNG_ALGORITHM L"RNG"
87 #endif
88 
89 #ifndef BCRYPT_MD5_ALGORITHM
90 #define BCRYPT_MD5_ALGORITHM L"MD5"
91 #endif
92 
93 #ifndef BCRYPT_SHA1_ALGORITHM
94 #define BCRYPT_SHA1_ALGORITHM L"SHA1"
95 #endif
96 
97 #ifndef BCRYPT_SHA256_ALGORITHM
98 #define BCRYPT_SHA256_ALGORITHM L"SHA256"
99 #endif
100 
101 #ifndef BCRYPT_SHA512_ALGORITHM
102 #define BCRYPT_SHA512_ALGORITHM L"SHA512"
103 #endif
104 
105 #ifndef BCRYPT_RSA_ALGORITHM
106 #define BCRYPT_RSA_ALGORITHM L"RSA"
107 #endif
108 
109 #ifndef BCRYPT_DSA_ALGORITHM
110 #define BCRYPT_DSA_ALGORITHM L"DSA"
111 #endif
112 
113 #ifndef BCRYPT_AES_ALGORITHM
114 #define BCRYPT_AES_ALGORITHM L"AES"
115 #endif
116 
117 #ifndef BCRYPT_RC4_ALGORITHM
118 #define BCRYPT_RC4_ALGORITHM L"RC4"
119 #endif
120 
121 #ifndef BCRYPT_3DES_ALGORITHM
122 #define BCRYPT_3DES_ALGORITHM L"3DES"
123 #endif
124 
125 #ifndef BCRYPT_ALG_HANDLE_HMAC_FLAG
126 #define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008
127 #endif
128 
129 #ifndef BCRYPT_DSA_PUBLIC_BLOB
130 #define BCRYPT_DSA_PUBLIC_BLOB L"DSAPUBLICBLOB"
131 #endif
132 
133 #ifndef BCRYPT_DSA_PUBLIC_MAGIC
134 #define BCRYPT_DSA_PUBLIC_MAGIC 0x42505344 /* DSPB */
135 #endif
136 
137 #ifndef BCRYPT_DSA_PRIVATE_BLOB
138 #define BCRYPT_DSA_PRIVATE_BLOB L"DSAPRIVATEBLOB"
139 #endif
140 
141 #ifndef BCRYPT_DSA_PRIVATE_MAGIC
142 #define BCRYPT_DSA_PRIVATE_MAGIC 0x56505344 /* DSPV */
143 #endif
144 
145 #ifndef BCRYPT_RSAPUBLIC_BLOB
146 #define BCRYPT_RSAPUBLIC_BLOB L"RSAPUBLICBLOB"
147 #endif
148 
149 #ifndef BCRYPT_RSAPUBLIC_MAGIC
150 #define BCRYPT_RSAPUBLIC_MAGIC 0x31415352 /* RSA1 */
151 #endif
152 
153 #ifndef BCRYPT_RSAFULLPRIVATE_BLOB
154 #define BCRYPT_RSAFULLPRIVATE_BLOB L"RSAFULLPRIVATEBLOB"
155 #endif
156 
157 #ifndef BCRYPT_RSAFULLPRIVATE_MAGIC
158 #define BCRYPT_RSAFULLPRIVATE_MAGIC 0x33415352 /* RSA3 */
159 #endif
160 
161 #ifndef BCRYPT_KEY_DATA_BLOB
162 #define BCRYPT_KEY_DATA_BLOB L"KeyDataBlob"
163 #endif
164 
165 #ifndef BCRYPT_MESSAGE_BLOCK_LENGTH
166 #define BCRYPT_MESSAGE_BLOCK_LENGTH L"MessageBlockLength"
167 #endif
168 
169 #ifndef BCRYPT_NO_KEY_VALIDATION
170 #define BCRYPT_NO_KEY_VALIDATION 0x00000008
171 #endif
172 
173 #ifndef BCRYPT_BLOCK_PADDING
174 #define BCRYPT_BLOCK_PADDING 0x00000001
175 #endif
176 
177 #ifndef BCRYPT_PAD_NONE
178 #define BCRYPT_PAD_NONE 0x00000001
179 #endif
180 
181 #ifndef BCRYPT_PAD_PKCS1
182 #define BCRYPT_PAD_PKCS1 0x00000002
183 #endif
184 
185 #ifndef BCRYPT_PAD_OAEP
186 #define BCRYPT_PAD_OAEP 0x00000004
187 #endif
188 
189 #ifndef BCRYPT_PAD_PSS
190 #define BCRYPT_PAD_PSS 0x00000008
191 #endif
192 
193 #ifndef CRYPT_STRING_ANY
194 #define CRYPT_STRING_ANY 0x00000007
195 #endif
196 
197 #ifndef LEGACY_RSAPRIVATE_BLOB
198 #define LEGACY_RSAPRIVATE_BLOB L"CAPIPRIVATEBLOB"
199 #endif
200 
201 #ifndef PKCS_RSA_PRIVATE_KEY
202 #define PKCS_RSA_PRIVATE_KEY (LPCSTR)43
203 #endif
204 
205 
206 /*******************************************************************/
207 /*
208  * Windows CNG backend: Generic functions
209  */
210 
211 void
_libssh2_wincng_init(void)212 _libssh2_wincng_init(void)
213 {
214     int ret;
215 
216     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG,
217                                       BCRYPT_RNG_ALGORITHM, NULL, 0);
218 
219     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5,
220                                       BCRYPT_MD5_ALGORITHM, NULL, 0);
221     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1,
222                                       BCRYPT_SHA1_ALGORITHM, NULL, 0);
223     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA256,
224                                       BCRYPT_SHA256_ALGORITHM, NULL, 0);
225     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512,
226                                       BCRYPT_SHA512_ALGORITHM, NULL, 0);
227 
228     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5,
229                                       BCRYPT_MD5_ALGORITHM, NULL,
230                                       BCRYPT_ALG_HANDLE_HMAC_FLAG);
231     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1,
232                                       BCRYPT_SHA1_ALGORITHM, NULL,
233                                       BCRYPT_ALG_HANDLE_HMAC_FLAG);
234     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA256,
235                                       BCRYPT_SHA256_ALGORITHM, NULL,
236                                       BCRYPT_ALG_HANDLE_HMAC_FLAG);
237     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512,
238                                       BCRYPT_SHA512_ALGORITHM, NULL,
239                                       BCRYPT_ALG_HANDLE_HMAC_FLAG);
240 
241     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA,
242                                       BCRYPT_RSA_ALGORITHM, NULL, 0);
243     (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA,
244                                       BCRYPT_DSA_ALGORITHM, NULL, 0);
245 
246     ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_CBC,
247                                       BCRYPT_AES_ALGORITHM, NULL, 0);
248     if(BCRYPT_SUCCESS(ret)) {
249         ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_CBC,
250                                 BCRYPT_CHAINING_MODE,
251                                 (PBYTE)BCRYPT_CHAIN_MODE_CBC,
252                                 sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
253         if(!BCRYPT_SUCCESS(ret)) {
254             (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0);
255         }
256     }
257 
258     ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_ECB,
259                                       BCRYPT_AES_ALGORITHM, NULL, 0);
260     if(BCRYPT_SUCCESS(ret)) {
261         ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_ECB,
262                                 BCRYPT_CHAINING_MODE,
263                                 (PBYTE)BCRYPT_CHAIN_MODE_ECB,
264                                 sizeof(BCRYPT_CHAIN_MODE_ECB), 0);
265         if(!BCRYPT_SUCCESS(ret)) {
266             (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_ECB, 0);
267         }
268     }
269 
270     ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRC4_NA,
271                                       BCRYPT_RC4_ALGORITHM, NULL, 0);
272     if(BCRYPT_SUCCESS(ret)) {
273         ret = BCryptSetProperty(_libssh2_wincng.hAlgRC4_NA,
274                                 BCRYPT_CHAINING_MODE,
275                                 (PBYTE)BCRYPT_CHAIN_MODE_NA,
276                                 sizeof(BCRYPT_CHAIN_MODE_NA), 0);
277         if(!BCRYPT_SUCCESS(ret)) {
278             (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0);
279         }
280     }
281 
282     ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlg3DES_CBC,
283                                       BCRYPT_3DES_ALGORITHM, NULL, 0);
284     if(BCRYPT_SUCCESS(ret)) {
285         ret = BCryptSetProperty(_libssh2_wincng.hAlg3DES_CBC,
286                                 BCRYPT_CHAINING_MODE,
287                                 (PBYTE)BCRYPT_CHAIN_MODE_CBC,
288                                 sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
289         if(!BCRYPT_SUCCESS(ret)) {
290             (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC,
291                                                0);
292         }
293     }
294 }
295 
296 void
_libssh2_wincng_free(void)297 _libssh2_wincng_free(void)
298 {
299     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRNG, 0);
300     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashMD5, 0);
301     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0);
302     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA256, 0);
303     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA512, 0);
304     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacMD5, 0);
305     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0);
306     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA256, 0);
307     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA512, 0);
308     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRSA, 0);
309     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDSA, 0);
310     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0);
311     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0);
312     (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0);
313 
314     memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng));
315 }
316 
317 int
_libssh2_wincng_random(void * buf,int len)318 _libssh2_wincng_random(void *buf, int len)
319 {
320     int ret;
321 
322     ret = BCryptGenRandom(_libssh2_wincng.hAlgRNG, buf, len, 0);
323 
324     return BCRYPT_SUCCESS(ret) ? 0 : -1;
325 }
326 
327 static void
_libssh2_wincng_safe_free(void * buf,int len)328 _libssh2_wincng_safe_free(void *buf, int len)
329 {
330 #ifndef LIBSSH2_CLEAR_MEMORY
331     (void)len;
332 #endif
333 
334     if(!buf)
335         return;
336 
337 #ifdef LIBSSH2_CLEAR_MEMORY
338     if(len > 0)
339         SecureZeroMemory(buf, len);
340 #endif
341 
342     free(buf);
343 }
344 
345 
346 /*******************************************************************/
347 /*
348  * Windows CNG backend: Hash functions
349  */
350 
351 int
_libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx * ctx,BCRYPT_ALG_HANDLE hAlg,unsigned long hashlen,unsigned char * key,unsigned long keylen)352 _libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx,
353                           BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen,
354                           unsigned char *key, unsigned long keylen)
355 {
356     BCRYPT_HASH_HANDLE hHash;
357     unsigned char *pbHashObject;
358     unsigned long dwHashObject, dwHash, cbData;
359     int ret;
360 
361     ret = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH,
362                             (unsigned char *)&dwHash,
363                             sizeof(dwHash),
364                             &cbData, 0);
365     if((!BCRYPT_SUCCESS(ret)) || dwHash != hashlen) {
366         return -1;
367     }
368 
369     ret = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH,
370                             (unsigned char *)&dwHashObject,
371                             sizeof(dwHashObject),
372                             &cbData, 0);
373     if(!BCRYPT_SUCCESS(ret)) {
374         return -1;
375     }
376 
377     pbHashObject = malloc(dwHashObject);
378     if(!pbHashObject) {
379         return -1;
380     }
381 
382 
383     ret = BCryptCreateHash(hAlg, &hHash,
384                            pbHashObject, dwHashObject,
385                            key, keylen, 0);
386     if(!BCRYPT_SUCCESS(ret)) {
387         _libssh2_wincng_safe_free(pbHashObject, dwHashObject);
388         return -1;
389     }
390 
391 
392     ctx->hHash = hHash;
393     ctx->pbHashObject = pbHashObject;
394     ctx->dwHashObject = dwHashObject;
395     ctx->cbHash = dwHash;
396 
397     return 0;
398 }
399 
400 int
_libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx * ctx,const unsigned char * data,unsigned long datalen)401 _libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx,
402                             const unsigned char *data, unsigned long datalen)
403 {
404     int ret;
405 
406     ret = BCryptHashData(ctx->hHash, (unsigned char *)data, datalen, 0);
407 
408     return BCRYPT_SUCCESS(ret) ? 0 : -1;
409 }
410 
411 int
_libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx * ctx,unsigned char * hash)412 _libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx,
413                            unsigned char *hash)
414 {
415     int ret;
416 
417     ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0);
418 
419     BCryptDestroyHash(ctx->hHash);
420     ctx->hHash = NULL;
421 
422     _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject);
423     ctx->pbHashObject = NULL;
424     ctx->dwHashObject = 0;
425 
426     return BCRYPT_SUCCESS(ret) ? 0 : -1;
427 }
428 
429 int
_libssh2_wincng_hash(unsigned char * data,unsigned long datalen,BCRYPT_ALG_HANDLE hAlg,unsigned char * hash,unsigned long hashlen)430 _libssh2_wincng_hash(unsigned char *data, unsigned long datalen,
431                      BCRYPT_ALG_HANDLE hAlg,
432                      unsigned char *hash, unsigned long hashlen)
433 {
434     _libssh2_wincng_hash_ctx ctx;
435     int ret;
436 
437     ret = _libssh2_wincng_hash_init(&ctx, hAlg, hashlen, NULL, 0);
438     if(!ret) {
439         ret = _libssh2_wincng_hash_update(&ctx, data, datalen);
440         ret |= _libssh2_wincng_hash_final(&ctx, hash);
441     }
442 
443     return ret;
444 }
445 
446 
447 /*******************************************************************/
448 /*
449  * Windows CNG backend: HMAC functions
450  */
451 
452 int
_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx * ctx,unsigned char * hash)453 _libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx,
454                            unsigned char *hash)
455 {
456     int ret;
457 
458     ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0);
459 
460     return BCRYPT_SUCCESS(ret) ? 0 : -1;
461 }
462 
463 void
_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx * ctx)464 _libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx)
465 {
466     BCryptDestroyHash(ctx->hHash);
467     ctx->hHash = NULL;
468 
469     _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject);
470     ctx->pbHashObject = NULL;
471     ctx->dwHashObject = 0;
472 }
473 
474 
475 /*******************************************************************/
476 /*
477  * Windows CNG backend: Key functions
478  */
479 
480 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)481 _libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx,
482                                 const unsigned char *sig,
483                                 unsigned long sig_len,
484                                 const unsigned char *m,
485                                 unsigned long m_len,
486                                 unsigned long flags)
487 {
488     BCRYPT_PKCS1_PADDING_INFO paddingInfoPKCS1;
489     void *pPaddingInfo;
490     unsigned char *data, *hash;
491     unsigned long datalen, hashlen;
492     int ret;
493 
494     datalen = m_len;
495     data = malloc(datalen);
496     if(!data) {
497         return -1;
498     }
499 
500     hashlen = SHA_DIGEST_LENGTH;
501     hash = malloc(hashlen);
502     if(!hash) {
503         free(data);
504         return -1;
505     }
506 
507     memcpy(data, m, datalen);
508 
509     ret = _libssh2_wincng_hash(data, datalen,
510                                _libssh2_wincng.hAlgHashSHA1,
511                                hash, hashlen);
512 
513     _libssh2_wincng_safe_free(data, datalen);
514 
515     if(ret) {
516         _libssh2_wincng_safe_free(hash, hashlen);
517         return -1;
518     }
519 
520     datalen = sig_len;
521     data = malloc(datalen);
522     if(!data) {
523         _libssh2_wincng_safe_free(hash, hashlen);
524         return -1;
525     }
526 
527     if(flags & BCRYPT_PAD_PKCS1) {
528         paddingInfoPKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM;
529         pPaddingInfo = &paddingInfoPKCS1;
530     }
531     else
532         pPaddingInfo = NULL;
533 
534     memcpy(data, sig, datalen);
535 
536     ret = BCryptVerifySignature(ctx->hKey, pPaddingInfo,
537                                 hash, hashlen, data, datalen, flags);
538 
539     _libssh2_wincng_safe_free(hash, hashlen);
540     _libssh2_wincng_safe_free(data, datalen);
541 
542     return BCRYPT_SUCCESS(ret) ? 0 : -1;
543 }
544 
545 #ifdef HAVE_LIBCRYPT32
546 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)547 _libssh2_wincng_load_pem(LIBSSH2_SESSION *session,
548                          const char *filename,
549                          const char *passphrase,
550                          const char *headerbegin,
551                          const char *headerend,
552                          unsigned char **data,
553                          unsigned int *datalen)
554 {
555     FILE *fp;
556     int ret;
557 
558     fp = fopen(filename, FOPEN_READTEXT);
559     if(!fp) {
560         return -1;
561     }
562 
563     ret = _libssh2_pem_parse(session, headerbegin, headerend,
564                              passphrase,
565                              fp, data, datalen);
566 
567     fclose(fp);
568 
569     return ret;
570 }
571 
572 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)573 _libssh2_wincng_load_private(LIBSSH2_SESSION *session,
574                              const char *filename,
575                              const char *passphrase,
576                              unsigned char **ppbEncoded,
577                              unsigned long *pcbEncoded,
578                              int tryLoadRSA, int tryLoadDSA)
579 {
580     unsigned char *data = NULL;
581     unsigned int datalen = 0;
582     int ret = -1;
583 
584     if(ret && tryLoadRSA) {
585         ret = _libssh2_wincng_load_pem(session, filename, passphrase,
586                                        PEM_RSA_HEADER, PEM_RSA_FOOTER,
587                                        &data, &datalen);
588     }
589 
590     if(ret && tryLoadDSA) {
591         ret = _libssh2_wincng_load_pem(session, filename, passphrase,
592                                        PEM_DSA_HEADER, PEM_DSA_FOOTER,
593                                        &data, &datalen);
594     }
595 
596     if(!ret) {
597         *ppbEncoded = data;
598         *pcbEncoded = datalen;
599     }
600 
601     return ret;
602 }
603 
604 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)605 _libssh2_wincng_load_private_memory(LIBSSH2_SESSION *session,
606                                     const char *privatekeydata,
607                                     size_t privatekeydata_len,
608                                     const char *passphrase,
609                                     unsigned char **ppbEncoded,
610                                     unsigned long *pcbEncoded,
611                                     int tryLoadRSA, int tryLoadDSA)
612 {
613     unsigned char *data = NULL;
614     unsigned int datalen = 0;
615     int ret = -1;
616 
617     (void)passphrase;
618 
619     if(ret && tryLoadRSA) {
620         ret = _libssh2_pem_parse_memory(session,
621                                         PEM_RSA_HEADER, PEM_RSA_FOOTER,
622                                         privatekeydata, privatekeydata_len,
623                                         &data, &datalen);
624     }
625 
626     if(ret && tryLoadDSA) {
627         ret = _libssh2_pem_parse_memory(session,
628                                         PEM_DSA_HEADER, PEM_DSA_FOOTER,
629                                         privatekeydata, privatekeydata_len,
630                                         &data, &datalen);
631     }
632 
633     if(!ret) {
634         *ppbEncoded = data;
635         *pcbEncoded = datalen;
636     }
637 
638     return ret;
639 }
640 
641 static int
_libssh2_wincng_asn_decode(unsigned char * pbEncoded,unsigned long cbEncoded,LPCSTR lpszStructType,unsigned char ** ppbDecoded,unsigned long * pcbDecoded)642 _libssh2_wincng_asn_decode(unsigned char *pbEncoded,
643                            unsigned long cbEncoded,
644                            LPCSTR lpszStructType,
645                            unsigned char **ppbDecoded,
646                            unsigned long *pcbDecoded)
647 {
648     unsigned char *pbDecoded = NULL;
649     unsigned long cbDecoded = 0;
650     int ret;
651 
652     ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
653                               lpszStructType,
654                               pbEncoded, cbEncoded, 0, NULL,
655                               NULL, &cbDecoded);
656     if(!ret) {
657         return -1;
658     }
659 
660     pbDecoded = malloc(cbDecoded);
661     if(!pbDecoded) {
662         return -1;
663     }
664 
665     ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
666                               lpszStructType,
667                               pbEncoded, cbEncoded, 0, NULL,
668                               pbDecoded, &cbDecoded);
669     if(!ret) {
670         _libssh2_wincng_safe_free(pbDecoded, cbDecoded);
671         return -1;
672     }
673 
674 
675     *ppbDecoded = pbDecoded;
676     *pcbDecoded = cbDecoded;
677 
678     return 0;
679 }
680 
681 static int
_libssh2_wincng_bn_ltob(unsigned char * pbInput,unsigned long cbInput,unsigned char ** ppbOutput,unsigned long * pcbOutput)682 _libssh2_wincng_bn_ltob(unsigned char *pbInput,
683                         unsigned long cbInput,
684                         unsigned char **ppbOutput,
685                         unsigned long *pcbOutput)
686 {
687     unsigned char *pbOutput;
688     unsigned long cbOutput, index, offset, length;
689 
690     if(cbInput < 1) {
691         return 0;
692     }
693 
694     offset = 0;
695     length = cbInput - 1;
696     cbOutput = cbInput;
697     if(pbInput[length] & (1 << 7)) {
698         offset++;
699         cbOutput += offset;
700     }
701 
702     pbOutput = (unsigned char *)malloc(cbOutput);
703     if(!pbOutput) {
704         return -1;
705     }
706 
707     pbOutput[0] = 0;
708     for(index = 0; ((index + offset) < cbOutput)
709                     && (index < cbInput); index++) {
710         pbOutput[index + offset] = pbInput[length - index];
711     }
712 
713 
714     *ppbOutput = pbOutput;
715     *pcbOutput = cbOutput;
716 
717     return 0;
718 }
719 
720 static int
_libssh2_wincng_asn_decode_bn(unsigned char * pbEncoded,unsigned long cbEncoded,unsigned char ** ppbDecoded,unsigned long * pcbDecoded)721 _libssh2_wincng_asn_decode_bn(unsigned char *pbEncoded,
722                               unsigned long cbEncoded,
723                               unsigned char **ppbDecoded,
724                               unsigned long *pcbDecoded)
725 {
726     unsigned char *pbDecoded = NULL, *pbInteger;
727     unsigned long cbDecoded = 0, cbInteger;
728     int ret;
729 
730     ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded,
731                                      X509_MULTI_BYTE_UINT,
732                                      &pbInteger, &cbInteger);
733     if(!ret) {
734         ret = _libssh2_wincng_bn_ltob(((PCRYPT_DATA_BLOB)pbInteger)->pbData,
735                                       ((PCRYPT_DATA_BLOB)pbInteger)->cbData,
736                                       &pbDecoded, &cbDecoded);
737         if(!ret) {
738             *ppbDecoded = pbDecoded;
739             *pcbDecoded = cbDecoded;
740         }
741         _libssh2_wincng_safe_free(pbInteger, cbInteger);
742     }
743 
744     return ret;
745 }
746 
747 static int
_libssh2_wincng_asn_decode_bns(unsigned char * pbEncoded,unsigned long cbEncoded,unsigned char *** prpbDecoded,unsigned long ** prcbDecoded,unsigned long * pcbCount)748 _libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded,
749                                unsigned long cbEncoded,
750                                unsigned char ***prpbDecoded,
751                                unsigned long **prcbDecoded,
752                                unsigned long *pcbCount)
753 {
754     PCRYPT_DER_BLOB pBlob;
755     unsigned char *pbDecoded, **rpbDecoded;
756     unsigned long cbDecoded, *rcbDecoded, index, length;
757     int ret;
758 
759     ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded,
760                                      X509_SEQUENCE_OF_ANY,
761                                      &pbDecoded, &cbDecoded);
762     if(!ret) {
763         length = ((PCRYPT_DATA_BLOB)pbDecoded)->cbData;
764 
765         rpbDecoded = malloc(sizeof(PBYTE) * length);
766         if(rpbDecoded) {
767             rcbDecoded = malloc(sizeof(DWORD) * length);
768             if(rcbDecoded) {
769                 for(index = 0; index < length; index++) {
770                     pBlob = &((PCRYPT_DER_BLOB)
771                               ((PCRYPT_DATA_BLOB)pbDecoded)->pbData)[index];
772                     ret = _libssh2_wincng_asn_decode_bn(pBlob->pbData,
773                                                         pBlob->cbData,
774                                                         &rpbDecoded[index],
775                                                         &rcbDecoded[index]);
776                     if(ret)
777                         break;
778                 }
779 
780                 if(!ret) {
781                     *prpbDecoded = rpbDecoded;
782                     *prcbDecoded = rcbDecoded;
783                     *pcbCount = length;
784                 }
785                 else {
786                     for(length = 0; length < index; length++) {
787                         _libssh2_wincng_safe_free(rpbDecoded[length],
788                                                   rcbDecoded[length]);
789                         rpbDecoded[length] = NULL;
790                         rcbDecoded[length] = 0;
791                     }
792                     free(rpbDecoded);
793                     free(rcbDecoded);
794                 }
795             }
796             else {
797                 free(rpbDecoded);
798                 ret = -1;
799             }
800         }
801         else {
802             ret = -1;
803         }
804 
805         _libssh2_wincng_safe_free(pbDecoded, cbDecoded);
806     }
807 
808     return ret;
809 }
810 #endif /* HAVE_LIBCRYPT32 */
811 
812 static unsigned long
_libssh2_wincng_bn_size(const unsigned char * bignum,unsigned long length)813 _libssh2_wincng_bn_size(const unsigned char *bignum,
814                         unsigned long length)
815 {
816     unsigned long offset;
817 
818     if(!bignum)
819         return 0;
820 
821     length--;
822 
823     offset = 0;
824     while(!(*(bignum + offset)) && (offset < length))
825         offset++;
826 
827     length++;
828 
829     return length - offset;
830 }
831 
832 
833 /*******************************************************************/
834 /*
835  * Windows CNG backend: RSA functions
836  */
837 
838 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)839 _libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa,
840                         const unsigned char *edata,
841                         unsigned long elen,
842                         const unsigned char *ndata,
843                         unsigned long nlen,
844                         const unsigned char *ddata,
845                         unsigned long dlen,
846                         const unsigned char *pdata,
847                         unsigned long plen,
848                         const unsigned char *qdata,
849                         unsigned long qlen,
850                         const unsigned char *e1data,
851                         unsigned long e1len,
852                         const unsigned char *e2data,
853                         unsigned long e2len,
854                         const unsigned char *coeffdata,
855                         unsigned long coefflen)
856 {
857     BCRYPT_KEY_HANDLE hKey;
858     BCRYPT_RSAKEY_BLOB *rsakey;
859     LPCWSTR lpszBlobType;
860     unsigned char *key;
861     unsigned long keylen, offset, mlen, p1len = 0, p2len = 0;
862     int ret;
863 
864     mlen = max(_libssh2_wincng_bn_size(ndata, nlen),
865                _libssh2_wincng_bn_size(ddata, dlen));
866     offset = sizeof(BCRYPT_RSAKEY_BLOB);
867     keylen = offset + elen + mlen;
868     if(ddata && dlen > 0) {
869         p1len = max(_libssh2_wincng_bn_size(pdata, plen),
870                     _libssh2_wincng_bn_size(e1data, e1len));
871         p2len = max(_libssh2_wincng_bn_size(qdata, qlen),
872                     _libssh2_wincng_bn_size(e2data, e2len));
873         keylen += p1len * 3 + p2len * 2 + mlen;
874     }
875 
876     key = malloc(keylen);
877     if(!key) {
878         return -1;
879     }
880 
881     memset(key, 0, keylen);
882 
883 
884     /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */
885     rsakey = (BCRYPT_RSAKEY_BLOB *)key;
886     rsakey->BitLength = mlen * 8;
887     rsakey->cbPublicExp = elen;
888     rsakey->cbModulus = mlen;
889 
890     memcpy(key + offset, edata, elen);
891     offset += elen;
892 
893     if(nlen < mlen)
894         memcpy(key + offset + mlen - nlen, ndata, nlen);
895     else
896         memcpy(key + offset, ndata + nlen - mlen, mlen);
897 
898     if(ddata && dlen > 0) {
899         offset += mlen;
900 
901         if(plen < p1len)
902             memcpy(key + offset + p1len - plen, pdata, plen);
903         else
904             memcpy(key + offset, pdata + plen - p1len, p1len);
905         offset += p1len;
906 
907         if(qlen < p2len)
908             memcpy(key + offset + p2len - qlen, qdata, qlen);
909         else
910             memcpy(key + offset, qdata + qlen - p2len, p2len);
911         offset += p2len;
912 
913         if(e1len < p1len)
914             memcpy(key + offset + p1len - e1len, e1data, e1len);
915         else
916             memcpy(key + offset, e1data + e1len - p1len, p1len);
917         offset += p1len;
918 
919         if(e2len < p2len)
920             memcpy(key + offset + p2len - e2len, e2data, e2len);
921         else
922             memcpy(key + offset, e2data + e2len - p2len, p2len);
923         offset += p2len;
924 
925         if(coefflen < p1len)
926             memcpy(key + offset + p1len - coefflen, coeffdata, coefflen);
927         else
928             memcpy(key + offset, coeffdata + coefflen - p1len, p1len);
929         offset += p1len;
930 
931         if(dlen < mlen)
932             memcpy(key + offset + mlen - dlen, ddata, dlen);
933         else
934             memcpy(key + offset, ddata + dlen - mlen, mlen);
935 
936         lpszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB;
937         rsakey->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC;
938         rsakey->cbPrime1 = p1len;
939         rsakey->cbPrime2 = p2len;
940     }
941     else {
942         lpszBlobType = BCRYPT_RSAPUBLIC_BLOB;
943         rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC;
944         rsakey->cbPrime1 = 0;
945         rsakey->cbPrime2 = 0;
946     }
947 
948 
949     ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, lpszBlobType,
950                               &hKey, key, keylen, 0);
951     if(!BCRYPT_SUCCESS(ret)) {
952         _libssh2_wincng_safe_free(key, keylen);
953         return -1;
954     }
955 
956 
957     *rsa = malloc(sizeof(libssh2_rsa_ctx));
958     if(!(*rsa)) {
959         BCryptDestroyKey(hKey);
960         _libssh2_wincng_safe_free(key, keylen);
961         return -1;
962     }
963 
964     (*rsa)->hKey = hKey;
965     (*rsa)->pbKeyObject = key;
966     (*rsa)->cbKeyObject = keylen;
967 
968     return 0;
969 }
970 
971 #ifdef HAVE_LIBCRYPT32
972 static int
_libssh2_wincng_rsa_new_private_parse(libssh2_rsa_ctx ** rsa,LIBSSH2_SESSION * session,unsigned char * pbEncoded,unsigned long cbEncoded)973 _libssh2_wincng_rsa_new_private_parse(libssh2_rsa_ctx **rsa,
974                                       LIBSSH2_SESSION *session,
975                                       unsigned char *pbEncoded,
976                                       unsigned long cbEncoded)
977 {
978     BCRYPT_KEY_HANDLE hKey;
979     unsigned char *pbStructInfo;
980     unsigned long cbStructInfo;
981     int ret;
982 
983     (void)session;
984 
985     ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded,
986                                      PKCS_RSA_PRIVATE_KEY,
987                                      &pbStructInfo, &cbStructInfo);
988 
989     _libssh2_wincng_safe_free(pbEncoded, cbEncoded);
990 
991     if(ret) {
992         return -1;
993     }
994 
995 
996     ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL,
997                               LEGACY_RSAPRIVATE_BLOB, &hKey,
998                               pbStructInfo, cbStructInfo, 0);
999     if(!BCRYPT_SUCCESS(ret)) {
1000         _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo);
1001         return -1;
1002     }
1003 
1004 
1005     *rsa = malloc(sizeof(libssh2_rsa_ctx));
1006     if(!(*rsa)) {
1007         BCryptDestroyKey(hKey);
1008         _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo);
1009         return -1;
1010     }
1011 
1012     (*rsa)->hKey = hKey;
1013     (*rsa)->pbKeyObject = pbStructInfo;
1014     (*rsa)->cbKeyObject = cbStructInfo;
1015 
1016     return 0;
1017 }
1018 #endif /* HAVE_LIBCRYPT32 */
1019 
1020 int
_libssh2_wincng_rsa_new_private(libssh2_rsa_ctx ** rsa,LIBSSH2_SESSION * session,const char * filename,const unsigned char * passphrase)1021 _libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa,
1022                                 LIBSSH2_SESSION *session,
1023                                 const char *filename,
1024                                 const unsigned char *passphrase)
1025 {
1026 #ifdef HAVE_LIBCRYPT32
1027     unsigned char *pbEncoded;
1028     unsigned long cbEncoded;
1029     int ret;
1030 
1031     (void)session;
1032 
1033     ret = _libssh2_wincng_load_private(session, filename,
1034                                        (const char *)passphrase,
1035                                        &pbEncoded, &cbEncoded, 1, 0);
1036     if(ret) {
1037         return -1;
1038     }
1039 
1040     return _libssh2_wincng_rsa_new_private_parse(rsa, session,
1041                                                  pbEncoded, cbEncoded);
1042 #else
1043     (void)rsa;
1044     (void)filename;
1045     (void)passphrase;
1046 
1047     return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1048                           "Unable to load RSA key from private key file: "
1049                           "Method unsupported in Windows CNG backend");
1050 #endif /* HAVE_LIBCRYPT32 */
1051 }
1052 
1053 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)1054 _libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa,
1055                                            LIBSSH2_SESSION *session,
1056                                            const char *filedata,
1057                                            size_t filedata_len,
1058                                            unsigned const char *passphrase)
1059 {
1060 #ifdef HAVE_LIBCRYPT32
1061     unsigned char *pbEncoded;
1062     unsigned long cbEncoded;
1063     int ret;
1064 
1065     (void)session;
1066 
1067     ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len,
1068                                               (const char *)passphrase,
1069                                               &pbEncoded, &cbEncoded, 1, 0);
1070     if(ret) {
1071         return -1;
1072     }
1073 
1074     return _libssh2_wincng_rsa_new_private_parse(rsa, session,
1075                                                  pbEncoded, cbEncoded);
1076 #else
1077     (void)rsa;
1078     (void)filedata;
1079     (void)filedata_len;
1080     (void)passphrase;
1081 
1082     return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
1083                           "Unable to extract private key from memory: "
1084                           "Method unsupported in Windows CNG backend");
1085 #endif /* HAVE_LIBCRYPT32 */
1086 }
1087 
1088 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)1089 _libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
1090                                 const unsigned char *sig,
1091                                 unsigned long sig_len,
1092                                 const unsigned char *m,
1093                                 unsigned long m_len)
1094 {
1095     return _libssh2_wincng_key_sha1_verify(rsa, sig, sig_len, m, m_len,
1096                                            BCRYPT_PAD_PKCS1);
1097 }
1098 
1099 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)1100 _libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session,
1101                               libssh2_rsa_ctx *rsa,
1102                               const unsigned char *hash,
1103                               size_t hash_len,
1104                               unsigned char **signature,
1105                               size_t *signature_len)
1106 {
1107     BCRYPT_PKCS1_PADDING_INFO paddingInfo;
1108     unsigned char *data, *sig;
1109     unsigned long cbData, datalen, siglen;
1110     int ret;
1111 
1112     datalen = (unsigned long)hash_len;
1113     data = malloc(datalen);
1114     if(!data) {
1115         return -1;
1116     }
1117 
1118     paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
1119 
1120     memcpy(data, hash, datalen);
1121 
1122     ret = BCryptSignHash(rsa->hKey, &paddingInfo,
1123                          data, datalen, NULL, 0,
1124                          &cbData, BCRYPT_PAD_PKCS1);
1125     if(BCRYPT_SUCCESS(ret)) {
1126         siglen = cbData;
1127         sig = LIBSSH2_ALLOC(session, siglen);
1128         if(sig) {
1129             ret = BCryptSignHash(rsa->hKey, &paddingInfo,
1130                                  data, datalen, sig, siglen,
1131                                  &cbData, BCRYPT_PAD_PKCS1);
1132             if(BCRYPT_SUCCESS(ret)) {
1133                 *signature_len = siglen;
1134                 *signature = sig;
1135             }
1136             else {
1137                 LIBSSH2_FREE(session, sig);
1138             }
1139         }
1140         else
1141             ret = STATUS_NO_MEMORY;
1142     }
1143 
1144     _libssh2_wincng_safe_free(data, datalen);
1145 
1146     return BCRYPT_SUCCESS(ret) ? 0 : -1;
1147 }
1148 
1149 void
_libssh2_wincng_rsa_free(libssh2_rsa_ctx * rsa)1150 _libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa)
1151 {
1152     if(!rsa)
1153         return;
1154 
1155     BCryptDestroyKey(rsa->hKey);
1156     rsa->hKey = NULL;
1157 
1158     _libssh2_wincng_safe_free(rsa->pbKeyObject, rsa->cbKeyObject);
1159     _libssh2_wincng_safe_free(rsa, sizeof(libssh2_rsa_ctx));
1160 }
1161 
1162 
1163 /*******************************************************************/
1164 /*
1165  * Windows CNG backend: DSA functions
1166  */
1167 
1168 #if LIBSSH2_DSA
1169 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)1170 _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa,
1171                         const unsigned char *pdata,
1172                         unsigned long plen,
1173                         const unsigned char *qdata,
1174                         unsigned long qlen,
1175                         const unsigned char *gdata,
1176                         unsigned long glen,
1177                         const unsigned char *ydata,
1178                         unsigned long ylen,
1179                         const unsigned char *xdata,
1180                         unsigned long xlen)
1181 {
1182     BCRYPT_KEY_HANDLE hKey;
1183     BCRYPT_DSA_KEY_BLOB *dsakey;
1184     LPCWSTR lpszBlobType;
1185     unsigned char *key;
1186     unsigned long keylen, offset, length;
1187     int ret;
1188 
1189     length = max(max(_libssh2_wincng_bn_size(pdata, plen),
1190                      _libssh2_wincng_bn_size(gdata, glen)),
1191                  _libssh2_wincng_bn_size(ydata, ylen));
1192     offset = sizeof(BCRYPT_DSA_KEY_BLOB);
1193     keylen = offset + length * 3;
1194     if(xdata && xlen > 0)
1195         keylen += 20;
1196 
1197     key = malloc(keylen);
1198     if(!key) {
1199         return -1;
1200     }
1201 
1202     memset(key, 0, keylen);
1203 
1204 
1205     /* https://msdn.microsoft.com/library/windows/desktop/aa833126.aspx */
1206     dsakey = (BCRYPT_DSA_KEY_BLOB *)key;
1207     dsakey->cbKey = length;
1208 
1209     memset(dsakey->Count, -1, sizeof(dsakey->Count));
1210     memset(dsakey->Seed, -1, sizeof(dsakey->Seed));
1211 
1212     if(qlen < 20)
1213         memcpy(dsakey->q + 20 - qlen, qdata, qlen);
1214     else
1215         memcpy(dsakey->q, qdata + qlen - 20, 20);
1216 
1217     if(plen < length)
1218         memcpy(key + offset + length - plen, pdata, plen);
1219     else
1220         memcpy(key + offset, pdata + plen - length, length);
1221     offset += length;
1222 
1223     if(glen < length)
1224         memcpy(key + offset + length - glen, gdata, glen);
1225     else
1226         memcpy(key + offset, gdata + glen - length, length);
1227     offset += length;
1228 
1229     if(ylen < length)
1230         memcpy(key + offset + length - ylen, ydata, ylen);
1231     else
1232         memcpy(key + offset, ydata + ylen - length, length);
1233 
1234     if(xdata && xlen > 0) {
1235         offset += length;
1236 
1237         if(xlen < 20)
1238             memcpy(key + offset + 20 - xlen, xdata, xlen);
1239         else
1240             memcpy(key + offset, xdata + xlen - 20, 20);
1241 
1242         lpszBlobType = BCRYPT_DSA_PRIVATE_BLOB;
1243         dsakey->dwMagic = BCRYPT_DSA_PRIVATE_MAGIC;
1244     }
1245     else {
1246         lpszBlobType = BCRYPT_DSA_PUBLIC_BLOB;
1247         dsakey->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC;
1248     }
1249 
1250 
1251     ret = BCryptImportKeyPair(_libssh2_wincng.hAlgDSA, NULL, lpszBlobType,
1252                               &hKey, key, keylen, 0);
1253     if(!BCRYPT_SUCCESS(ret)) {
1254         _libssh2_wincng_safe_free(key, keylen);
1255         return -1;
1256     }
1257 
1258 
1259     *dsa = malloc(sizeof(libssh2_dsa_ctx));
1260     if(!(*dsa)) {
1261         BCryptDestroyKey(hKey);
1262         _libssh2_wincng_safe_free(key, keylen);
1263         return -1;
1264     }
1265 
1266     (*dsa)->hKey = hKey;
1267     (*dsa)->pbKeyObject = key;
1268     (*dsa)->cbKeyObject = keylen;
1269 
1270     return 0;
1271 }
1272 
1273 #ifdef HAVE_LIBCRYPT32
1274 static int
_libssh2_wincng_dsa_new_private_parse(libssh2_dsa_ctx ** dsa,LIBSSH2_SESSION * session,unsigned char * pbEncoded,unsigned long cbEncoded)1275 _libssh2_wincng_dsa_new_private_parse(libssh2_dsa_ctx **dsa,
1276                                       LIBSSH2_SESSION *session,
1277                                       unsigned char *pbEncoded,
1278                                       unsigned long cbEncoded)
1279 {
1280     unsigned char **rpbDecoded;
1281     unsigned long *rcbDecoded, index, length;
1282     int ret;
1283 
1284     (void)session;
1285 
1286     ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded,
1287                                          &rpbDecoded, &rcbDecoded, &length);
1288 
1289     _libssh2_wincng_safe_free(pbEncoded, cbEncoded);
1290 
1291     if(ret) {
1292         return -1;
1293     }
1294 
1295 
1296     if(length == 6) {
1297         ret = _libssh2_wincng_dsa_new(dsa,
1298                                       rpbDecoded[1], rcbDecoded[1],
1299                                       rpbDecoded[2], rcbDecoded[2],
1300                                       rpbDecoded[3], rcbDecoded[3],
1301                                       rpbDecoded[4], rcbDecoded[4],
1302                                       rpbDecoded[5], rcbDecoded[5]);
1303     }
1304     else {
1305         ret = -1;
1306     }
1307 
1308     for(index = 0; index < length; index++) {
1309         _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]);
1310         rpbDecoded[index] = NULL;
1311         rcbDecoded[index] = 0;
1312     }
1313 
1314     free(rpbDecoded);
1315     free(rcbDecoded);
1316 
1317     return ret;
1318 }
1319 #endif /* HAVE_LIBCRYPT32 */
1320 
1321 int
_libssh2_wincng_dsa_new_private(libssh2_dsa_ctx ** dsa,LIBSSH2_SESSION * session,const char * filename,const unsigned char * passphrase)1322 _libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa,
1323                                 LIBSSH2_SESSION *session,
1324                                 const char *filename,
1325                                 const unsigned char *passphrase)
1326 {
1327 #ifdef HAVE_LIBCRYPT32
1328     unsigned char *pbEncoded;
1329     unsigned long cbEncoded;
1330     int ret;
1331 
1332     ret = _libssh2_wincng_load_private(session, filename,
1333                                        (const char *)passphrase,
1334                                        &pbEncoded, &cbEncoded, 0, 1);
1335     if(ret) {
1336         return -1;
1337     }
1338 
1339     return _libssh2_wincng_dsa_new_private_parse(dsa, session,
1340                                                  pbEncoded, cbEncoded);
1341 #else
1342     (void)dsa;
1343     (void)filename;
1344     (void)passphrase;
1345 
1346     return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1347                           "Unable to load DSA key from private key file: "
1348                           "Method unsupported in Windows CNG backend");
1349 #endif /* HAVE_LIBCRYPT32 */
1350 }
1351 
1352 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)1353 _libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa,
1354                                            LIBSSH2_SESSION *session,
1355                                            const char *filedata,
1356                                            size_t filedata_len,
1357                                            unsigned const char *passphrase)
1358 {
1359 #ifdef HAVE_LIBCRYPT32
1360     unsigned char *pbEncoded;
1361     unsigned long cbEncoded;
1362     int ret;
1363 
1364     ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len,
1365                                               (const char *)passphrase,
1366                                               &pbEncoded, &cbEncoded, 0, 1);
1367     if(ret) {
1368         return -1;
1369     }
1370 
1371     return _libssh2_wincng_dsa_new_private_parse(dsa, session,
1372                                                  pbEncoded, cbEncoded);
1373 #else
1374     (void)dsa;
1375     (void)filedata;
1376     (void)filedata_len;
1377     (void)passphrase;
1378 
1379     return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
1380                           "Unable to extract private key from memory: "
1381                           "Method unsupported in Windows CNG backend");
1382 #endif /* HAVE_LIBCRYPT32 */
1383 }
1384 
1385 int
_libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx * dsa,const unsigned char * sig_fixed,const unsigned char * m,unsigned long m_len)1386 _libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa,
1387                                 const unsigned char *sig_fixed,
1388                                 const unsigned char *m,
1389                                 unsigned long m_len)
1390 {
1391     return _libssh2_wincng_key_sha1_verify(dsa, sig_fixed, 40, m, m_len, 0);
1392 }
1393 
1394 int
_libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx * dsa,const unsigned char * hash,unsigned long hash_len,unsigned char * sig_fixed)1395 _libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa,
1396                               const unsigned char *hash,
1397                               unsigned long hash_len,
1398                               unsigned char *sig_fixed)
1399 {
1400     unsigned char *data, *sig;
1401     unsigned long cbData, datalen, siglen;
1402     int ret;
1403 
1404     datalen = hash_len;
1405     data = malloc(datalen);
1406     if(!data) {
1407         return -1;
1408     }
1409 
1410     memcpy(data, hash, datalen);
1411 
1412     ret = BCryptSignHash(dsa->hKey, NULL, data, datalen,
1413                          NULL, 0, &cbData, 0);
1414     if(BCRYPT_SUCCESS(ret)) {
1415         siglen = cbData;
1416         if(siglen == 40) {
1417             sig = malloc(siglen);
1418             if(sig) {
1419                 ret = BCryptSignHash(dsa->hKey, NULL, data, datalen,
1420                                      sig, siglen, &cbData, 0);
1421                 if(BCRYPT_SUCCESS(ret)) {
1422                     memcpy(sig_fixed, sig, siglen);
1423                 }
1424 
1425                 _libssh2_wincng_safe_free(sig, siglen);
1426             }
1427             else
1428                 ret = STATUS_NO_MEMORY;
1429         }
1430         else
1431             ret = STATUS_NO_MEMORY;
1432     }
1433 
1434     _libssh2_wincng_safe_free(data, datalen);
1435 
1436     return BCRYPT_SUCCESS(ret) ? 0 : -1;
1437 }
1438 
1439 void
_libssh2_wincng_dsa_free(libssh2_dsa_ctx * dsa)1440 _libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa)
1441 {
1442     if(!dsa)
1443         return;
1444 
1445     BCryptDestroyKey(dsa->hKey);
1446     dsa->hKey = NULL;
1447 
1448     _libssh2_wincng_safe_free(dsa->pbKeyObject, dsa->cbKeyObject);
1449     _libssh2_wincng_safe_free(dsa, sizeof(libssh2_dsa_ctx));
1450 }
1451 #endif
1452 
1453 
1454 /*******************************************************************/
1455 /*
1456  * Windows CNG backend: Key functions
1457  */
1458 
1459 #ifdef HAVE_LIBCRYPT32
1460 static unsigned long
_libssh2_wincng_pub_priv_write(unsigned char * key,unsigned long offset,const unsigned char * bignum,const unsigned long length)1461 _libssh2_wincng_pub_priv_write(unsigned char *key,
1462                                unsigned long offset,
1463                                const unsigned char *bignum,
1464                                const unsigned long length)
1465 {
1466     _libssh2_htonu32(key + offset, length);
1467     offset += 4;
1468 
1469     memcpy(key + offset, bignum, length);
1470     offset += length;
1471 
1472     return offset;
1473 }
1474 
1475 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)1476 _libssh2_wincng_pub_priv_keyfile_parse(LIBSSH2_SESSION *session,
1477                                        unsigned char **method,
1478                                        size_t *method_len,
1479                                        unsigned char **pubkeydata,
1480                                        size_t *pubkeydata_len,
1481                                        unsigned char *pbEncoded,
1482                                        unsigned long cbEncoded)
1483 {
1484     unsigned char **rpbDecoded;
1485     unsigned long *rcbDecoded;
1486     unsigned char *key = NULL, *mth = NULL;
1487     unsigned long keylen = 0, mthlen = 0;
1488     unsigned long index, offset, length;
1489     int ret;
1490 
1491     ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded,
1492                                          &rpbDecoded, &rcbDecoded, &length);
1493 
1494     _libssh2_wincng_safe_free(pbEncoded, cbEncoded);
1495 
1496     if(ret) {
1497         return -1;
1498     }
1499 
1500 
1501     if(length == 9) { /* private RSA key */
1502         mthlen = 7;
1503         mth = LIBSSH2_ALLOC(session, mthlen);
1504         if(mth) {
1505             memcpy(mth, "ssh-rsa", mthlen);
1506         }
1507         else {
1508             ret = -1;
1509         }
1510 
1511 
1512         keylen = 4 + mthlen + 4 + rcbDecoded[2] + 4 + rcbDecoded[1];
1513         key = LIBSSH2_ALLOC(session, keylen);
1514         if(key) {
1515             offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen);
1516 
1517             offset = _libssh2_wincng_pub_priv_write(key, offset,
1518                                                     rpbDecoded[2],
1519                                                     rcbDecoded[2]);
1520 
1521             _libssh2_wincng_pub_priv_write(key, offset,
1522                                            rpbDecoded[1],
1523                                            rcbDecoded[1]);
1524         }
1525         else {
1526             ret = -1;
1527         }
1528 
1529     }
1530     else if(length == 6) { /* private DSA key */
1531         mthlen = 7;
1532         mth = LIBSSH2_ALLOC(session, mthlen);
1533         if(mth) {
1534             memcpy(mth, "ssh-dss", mthlen);
1535         }
1536         else {
1537             ret = -1;
1538         }
1539 
1540         keylen = 4 + mthlen + 4 + rcbDecoded[1] + 4 + rcbDecoded[2]
1541                             + 4 + rcbDecoded[3] + 4 + rcbDecoded[4];
1542         key = LIBSSH2_ALLOC(session, keylen);
1543         if(key) {
1544             offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen);
1545 
1546             offset = _libssh2_wincng_pub_priv_write(key, offset,
1547                                                     rpbDecoded[1],
1548                                                     rcbDecoded[1]);
1549 
1550             offset = _libssh2_wincng_pub_priv_write(key, offset,
1551                                                     rpbDecoded[2],
1552                                                     rcbDecoded[2]);
1553 
1554             offset = _libssh2_wincng_pub_priv_write(key, offset,
1555                                                     rpbDecoded[3],
1556                                                     rcbDecoded[3]);
1557 
1558             _libssh2_wincng_pub_priv_write(key, offset,
1559                                            rpbDecoded[4],
1560                                            rcbDecoded[4]);
1561         }
1562         else {
1563             ret = -1;
1564         }
1565 
1566     }
1567     else {
1568         ret = -1;
1569     }
1570 
1571 
1572     for(index = 0; index < length; index++) {
1573         _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]);
1574         rpbDecoded[index] = NULL;
1575         rcbDecoded[index] = 0;
1576     }
1577 
1578     free(rpbDecoded);
1579     free(rcbDecoded);
1580 
1581 
1582     if(ret) {
1583         if(mth)
1584             LIBSSH2_FREE(session, mth);
1585         if(key)
1586             LIBSSH2_FREE(session, key);
1587     }
1588     else {
1589         *method = mth;
1590         *method_len = mthlen;
1591         *pubkeydata = key;
1592         *pubkeydata_len = keylen;
1593     }
1594 
1595     return ret;
1596 }
1597 #endif /* HAVE_LIBCRYPT32 */
1598 
1599 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)1600 _libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session,
1601                                  unsigned char **method,
1602                                  size_t *method_len,
1603                                  unsigned char **pubkeydata,
1604                                  size_t *pubkeydata_len,
1605                                  const char *privatekey,
1606                                  const char *passphrase)
1607 {
1608 #ifdef HAVE_LIBCRYPT32
1609     unsigned char *pbEncoded;
1610     unsigned long cbEncoded;
1611     int ret;
1612 
1613     ret = _libssh2_wincng_load_private(session, privatekey, passphrase,
1614                                        &pbEncoded, &cbEncoded, 1, 1);
1615     if(ret) {
1616         return -1;
1617     }
1618 
1619     return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len,
1620                                                   pubkeydata, pubkeydata_len,
1621                                                   pbEncoded, cbEncoded);
1622 #else
1623     (void)method;
1624     (void)method_len;
1625     (void)pubkeydata;
1626     (void)pubkeydata_len;
1627     (void)privatekey;
1628     (void)passphrase;
1629 
1630     return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1631                           "Unable to load public key from private key file: "
1632                           "Method unsupported in Windows CNG backend");
1633 #endif /* HAVE_LIBCRYPT32 */
1634 }
1635 
1636 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)1637 _libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
1638                                        unsigned char **method,
1639                                        size_t *method_len,
1640                                        unsigned char **pubkeydata,
1641                                        size_t *pubkeydata_len,
1642                                        const char *privatekeydata,
1643                                        size_t privatekeydata_len,
1644                                        const char *passphrase)
1645 {
1646 #ifdef HAVE_LIBCRYPT32
1647     unsigned char *pbEncoded;
1648     unsigned long cbEncoded;
1649     int ret;
1650 
1651     ret = _libssh2_wincng_load_private_memory(session, privatekeydata,
1652                                               privatekeydata_len, passphrase,
1653                                               &pbEncoded, &cbEncoded, 1, 1);
1654     if(ret) {
1655         return -1;
1656     }
1657 
1658     return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len,
1659                                                   pubkeydata, pubkeydata_len,
1660                                                   pbEncoded, cbEncoded);
1661 #else
1662     (void)method;
1663     (void)method_len;
1664     (void)pubkeydata_len;
1665     (void)pubkeydata;
1666     (void)privatekeydata;
1667     (void)privatekeydata_len;
1668     (void)passphrase;
1669 
1670     return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
1671                "Unable to extract public key from private key in memory: "
1672                "Method unsupported in Windows CNG backend");
1673 #endif /* HAVE_LIBCRYPT32 */
1674 }
1675 
1676 /*******************************************************************/
1677 /*
1678  * Windows CNG backend: Cipher functions
1679  */
1680 
1681 int
_libssh2_wincng_cipher_init(_libssh2_cipher_ctx * ctx,_libssh2_cipher_type (type),unsigned char * iv,unsigned char * secret,int encrypt)1682 _libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx,
1683                             _libssh2_cipher_type(type),
1684                             unsigned char *iv,
1685                             unsigned char *secret,
1686                             int encrypt)
1687 {
1688     BCRYPT_KEY_HANDLE hKey;
1689     BCRYPT_KEY_DATA_BLOB_HEADER *header;
1690     unsigned char *pbKeyObject, *pbIV, *key, *pbCtr, *pbIVCopy;
1691     unsigned long dwKeyObject, dwIV, dwCtrLength, dwBlockLength,
1692                   cbData, keylen;
1693     int ret;
1694 
1695     (void)encrypt;
1696 
1697     ret = BCryptGetProperty(*type.phAlg, BCRYPT_OBJECT_LENGTH,
1698                             (unsigned char *)&dwKeyObject,
1699                             sizeof(dwKeyObject),
1700                             &cbData, 0);
1701     if(!BCRYPT_SUCCESS(ret)) {
1702         return -1;
1703     }
1704 
1705     ret = BCryptGetProperty(*type.phAlg, BCRYPT_BLOCK_LENGTH,
1706                             (unsigned char *)&dwBlockLength,
1707                             sizeof(dwBlockLength),
1708                             &cbData, 0);
1709     if(!BCRYPT_SUCCESS(ret)) {
1710         return -1;
1711     }
1712 
1713     pbKeyObject = malloc(dwKeyObject);
1714     if(!pbKeyObject) {
1715         return -1;
1716     }
1717 
1718 
1719     keylen = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + type.dwKeyLength;
1720     key = malloc(keylen);
1721     if(!key) {
1722         free(pbKeyObject);
1723         return -1;
1724     }
1725 
1726 
1727     header = (BCRYPT_KEY_DATA_BLOB_HEADER *)key;
1728     header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
1729     header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
1730     header->cbKeyData = type.dwKeyLength;
1731 
1732     memcpy(key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER),
1733            secret, type.dwKeyLength);
1734 
1735     ret = BCryptImportKey(*type.phAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey,
1736                           pbKeyObject, dwKeyObject, key, keylen, 0);
1737 
1738     _libssh2_wincng_safe_free(key, keylen);
1739 
1740     if(!BCRYPT_SUCCESS(ret)) {
1741         _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject);
1742         return -1;
1743     }
1744 
1745     pbIV = NULL;
1746     pbCtr = NULL;
1747     dwIV = 0;
1748     dwCtrLength = 0;
1749 
1750     if(type.useIV || type.ctrMode) {
1751         pbIVCopy = malloc(dwBlockLength);
1752         if(!pbIVCopy) {
1753             BCryptDestroyKey(hKey);
1754             _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject);
1755             return -1;
1756         }
1757         memcpy(pbIVCopy, iv, dwBlockLength);
1758 
1759         if(type.ctrMode) {
1760             pbCtr = pbIVCopy;
1761             dwCtrLength = dwBlockLength;
1762         }
1763         else if(type.useIV) {
1764             pbIV = pbIVCopy;
1765             dwIV = dwBlockLength;
1766         }
1767     }
1768 
1769     ctx->hKey = hKey;
1770     ctx->pbKeyObject = pbKeyObject;
1771     ctx->pbIV = pbIV;
1772     ctx->pbCtr = pbCtr;
1773     ctx->dwKeyObject = dwKeyObject;
1774     ctx->dwIV = dwIV;
1775     ctx->dwBlockLength = dwBlockLength;
1776     ctx->dwCtrLength = dwCtrLength;
1777 
1778     return 0;
1779 }
1780 int
_libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx * ctx,_libssh2_cipher_type (type),int encrypt,unsigned char * block,size_t blocklen)1781 _libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx,
1782                              _libssh2_cipher_type(type),
1783                              int encrypt,
1784                              unsigned char *block,
1785                              size_t blocklen)
1786 {
1787     unsigned char *pbOutput, *pbInput;
1788     unsigned long cbOutput, cbInput;
1789     int ret;
1790 
1791     (void)type;
1792 
1793     cbInput = (unsigned long)blocklen;
1794 
1795     if(type.ctrMode) {
1796         pbInput = ctx->pbCtr;
1797     }
1798     else {
1799         pbInput = block;
1800     }
1801 
1802     if(encrypt || type.ctrMode) {
1803         ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL,
1804                             ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0);
1805     }
1806     else {
1807         ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL,
1808                             ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0);
1809     }
1810     if(BCRYPT_SUCCESS(ret)) {
1811         pbOutput = malloc(cbOutput);
1812         if(pbOutput) {
1813             if(encrypt || type.ctrMode) {
1814                 ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL,
1815                                     ctx->pbIV, ctx->dwIV,
1816                                     pbOutput, cbOutput, &cbOutput, 0);
1817             }
1818             else {
1819                 ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL,
1820                                     ctx->pbIV, ctx->dwIV,
1821                                     pbOutput, cbOutput, &cbOutput, 0);
1822             }
1823             if(BCRYPT_SUCCESS(ret)) {
1824                 if(type.ctrMode) {
1825                     _libssh2_xor_data(block, block, pbOutput, blocklen);
1826                     _libssh2_aes_ctr_increment(ctx->pbCtr, ctx->dwCtrLength);
1827                 }
1828                 else {
1829                     memcpy(block, pbOutput, cbOutput);
1830                 }
1831             }
1832 
1833             _libssh2_wincng_safe_free(pbOutput, cbOutput);
1834         }
1835         else
1836             ret = STATUS_NO_MEMORY;
1837     }
1838 
1839     return BCRYPT_SUCCESS(ret) ? 0 : -1;
1840 }
1841 
1842 void
_libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx * ctx)1843 _libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx)
1844 {
1845     BCryptDestroyKey(ctx->hKey);
1846     ctx->hKey = NULL;
1847 
1848     _libssh2_wincng_safe_free(ctx->pbKeyObject, ctx->dwKeyObject);
1849     ctx->pbKeyObject = NULL;
1850     ctx->dwKeyObject = 0;
1851 
1852     _libssh2_wincng_safe_free(ctx->pbIV, ctx->dwBlockLength);
1853     ctx->pbIV = NULL;
1854     ctx->dwBlockLength = 0;
1855 
1856     _libssh2_wincng_safe_free(ctx->pbCtr, ctx->dwCtrLength);
1857     ctx->pbCtr = NULL;
1858     ctx->dwCtrLength = 0;
1859 }
1860 
1861 
1862 /*******************************************************************/
1863 /*
1864  * Windows CNG backend: BigNumber functions
1865  */
1866 
1867 _libssh2_bn *
_libssh2_wincng_bignum_init(void)1868 _libssh2_wincng_bignum_init(void)
1869 {
1870     _libssh2_bn *bignum;
1871 
1872     bignum = (_libssh2_bn *)malloc(sizeof(_libssh2_bn));
1873     if(bignum) {
1874         bignum->bignum = NULL;
1875         bignum->length = 0;
1876     }
1877 
1878     return bignum;
1879 }
1880 
1881 static int
_libssh2_wincng_bignum_resize(_libssh2_bn * bn,unsigned long length)1882 _libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length)
1883 {
1884     unsigned char *bignum;
1885 
1886     if(!bn)
1887         return -1;
1888 
1889     if(length == bn->length)
1890         return 0;
1891 
1892 #ifdef LIBSSH2_CLEAR_MEMORY
1893     if(bn->bignum && bn->length > 0 && length < bn->length) {
1894         SecureZeroMemory(bn->bignum + length, bn->length - length);
1895     }
1896 #endif
1897 
1898     bignum = realloc(bn->bignum, length);
1899     if(!bignum)
1900         return -1;
1901 
1902     bn->bignum = bignum;
1903     bn->length = length;
1904 
1905     return 0;
1906 }
1907 
1908 static int
_libssh2_wincng_bignum_rand(_libssh2_bn * rnd,int bits,int top,int bottom)1909 _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom)
1910 {
1911     unsigned char *bignum;
1912     unsigned long length;
1913 
1914     if(!rnd)
1915         return -1;
1916 
1917     length = (unsigned long)(ceil((float)bits / 8) * sizeof(unsigned char));
1918     if(_libssh2_wincng_bignum_resize(rnd, length))
1919         return -1;
1920 
1921     bignum = rnd->bignum;
1922 
1923     if(_libssh2_wincng_random(bignum, length))
1924         return -1;
1925 
1926     /* calculate significant bits in most significant byte */
1927     bits %= 8;
1928 
1929     /* fill most significant byte with zero padding */
1930     bignum[0] &= (1 << (8 - bits)) - 1;
1931 
1932     /* set some special last bits in most significant byte */
1933     if(top == 0)
1934         bignum[0] |= (1 << (7 - bits));
1935     else if(top == 1)
1936         bignum[0] |= (3 << (6 - bits));
1937 
1938     /* make odd by setting first bit in least significant byte */
1939     if(bottom)
1940         bignum[length - 1] |= 1;
1941 
1942     return 0;
1943 }
1944 
1945 static int
_libssh2_wincng_bignum_mod_exp(_libssh2_bn * r,_libssh2_bn * a,_libssh2_bn * p,_libssh2_bn * m)1946 _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r,
1947                                _libssh2_bn *a,
1948                                _libssh2_bn *p,
1949                                _libssh2_bn *m)
1950 {
1951     BCRYPT_KEY_HANDLE hKey;
1952     BCRYPT_RSAKEY_BLOB *rsakey;
1953     unsigned char *key, *bignum;
1954     unsigned long keylen, offset, length;
1955     int ret;
1956 
1957     if(!r || !a || !p || !m)
1958         return -1;
1959 
1960     offset = sizeof(BCRYPT_RSAKEY_BLOB);
1961     keylen = offset + p->length + m->length;
1962 
1963     key = malloc(keylen);
1964     if(!key)
1965         return -1;
1966 
1967 
1968     /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */
1969     rsakey = (BCRYPT_RSAKEY_BLOB *)key;
1970     rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC;
1971     rsakey->BitLength = m->length * 8;
1972     rsakey->cbPublicExp = p->length;
1973     rsakey->cbModulus = m->length;
1974     rsakey->cbPrime1 = 0;
1975     rsakey->cbPrime2 = 0;
1976 
1977     memcpy(key + offset, p->bignum, p->length);
1978     offset += p->length;
1979 
1980     memcpy(key + offset, m->bignum, m->length);
1981 
1982     ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL,
1983                               BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen,
1984                               BCRYPT_NO_KEY_VALIDATION);
1985 
1986     if(BCRYPT_SUCCESS(ret)) {
1987         ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0,
1988                             NULL, 0, &length, BCRYPT_PAD_NONE);
1989         if(BCRYPT_SUCCESS(ret)) {
1990             if(!_libssh2_wincng_bignum_resize(r, length)) {
1991                 length = max(a->length, length);
1992                 bignum = malloc(length);
1993                 if(bignum) {
1994                     offset = length - a->length;
1995                     memset(bignum, 0, offset);
1996                     memcpy(bignum + offset, a->bignum, a->length);
1997 
1998                     ret = BCryptEncrypt(hKey, bignum, length, NULL, NULL, 0,
1999                                         r->bignum, r->length, &offset,
2000                                         BCRYPT_PAD_NONE);
2001 
2002                     _libssh2_wincng_safe_free(bignum, length);
2003 
2004                     if(BCRYPT_SUCCESS(ret)) {
2005                         _libssh2_wincng_bignum_resize(r, offset);
2006                     }
2007                 }
2008                 else
2009                     ret = STATUS_NO_MEMORY;
2010             }
2011             else
2012                 ret = STATUS_NO_MEMORY;
2013         }
2014 
2015         BCryptDestroyKey(hKey);
2016     }
2017 
2018     _libssh2_wincng_safe_free(key, keylen);
2019 
2020     return BCRYPT_SUCCESS(ret) ? 0 : -1;
2021 }
2022 
2023 int
_libssh2_wincng_bignum_set_word(_libssh2_bn * bn,unsigned long word)2024 _libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word)
2025 {
2026     unsigned long offset, number, bits, length;
2027 
2028     if(!bn)
2029         return -1;
2030 
2031     bits = 0;
2032     number = word;
2033     while(number >>= 1)
2034         bits++;
2035 
2036     length = (unsigned long) (ceil(((double)(bits + 1)) / 8.0) *
2037                               sizeof(unsigned char));
2038     if(_libssh2_wincng_bignum_resize(bn, length))
2039         return -1;
2040 
2041     for(offset = 0; offset < length; offset++)
2042         bn->bignum[offset] = (word >> (offset * 8)) & 0xff;
2043 
2044     return 0;
2045 }
2046 
2047 unsigned long
_libssh2_wincng_bignum_bits(const _libssh2_bn * bn)2048 _libssh2_wincng_bignum_bits(const _libssh2_bn *bn)
2049 {
2050     unsigned char number;
2051     unsigned long offset, length, bits;
2052 
2053     if(!bn)
2054         return 0;
2055 
2056     length = bn->length - 1;
2057 
2058     offset = 0;
2059     while(!(*(bn->bignum + offset)) && (offset < length))
2060         offset++;
2061 
2062     bits = (length - offset) * 8;
2063     number = bn->bignum[offset];
2064 
2065     while(number >>= 1)
2066         bits++;
2067 
2068     bits++;
2069 
2070     return bits;
2071 }
2072 
2073 void
_libssh2_wincng_bignum_from_bin(_libssh2_bn * bn,unsigned long len,const unsigned char * bin)2074 _libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len,
2075                                 const unsigned char *bin)
2076 {
2077     unsigned char *bignum;
2078     unsigned long offset, length, bits;
2079 
2080     if(!bn || !bin || !len)
2081         return;
2082 
2083     if(_libssh2_wincng_bignum_resize(bn, len))
2084         return;
2085 
2086     memcpy(bn->bignum, bin, len);
2087 
2088     bits = _libssh2_wincng_bignum_bits(bn);
2089     length = (unsigned long) (ceil(((double)bits) / 8.0) *
2090                               sizeof(unsigned char));
2091 
2092     offset = bn->length - length;
2093     if(offset > 0) {
2094         memmove(bn->bignum, bn->bignum + offset, length);
2095 
2096 #ifdef LIBSSH2_CLEAR_MEMORY
2097         SecureZeroMemory(bn->bignum + length, offset);
2098 #endif
2099 
2100         bignum = realloc(bn->bignum, length);
2101         if(bignum) {
2102             bn->bignum = bignum;
2103             bn->length = length;
2104         }
2105     }
2106 }
2107 
2108 void
_libssh2_wincng_bignum_to_bin(const _libssh2_bn * bn,unsigned char * bin)2109 _libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin)
2110 {
2111     if(bin && bn && bn->bignum && bn->length > 0) {
2112         memcpy(bin, bn->bignum, bn->length);
2113     }
2114 }
2115 
2116 void
_libssh2_wincng_bignum_free(_libssh2_bn * bn)2117 _libssh2_wincng_bignum_free(_libssh2_bn *bn)
2118 {
2119     if(bn) {
2120         if(bn->bignum) {
2121             _libssh2_wincng_safe_free(bn->bignum, bn->length);
2122             bn->bignum = NULL;
2123         }
2124         bn->length = 0;
2125         _libssh2_wincng_safe_free(bn, sizeof(_libssh2_bn));
2126     }
2127 }
2128 
2129 
2130 /*
2131  * Windows CNG backend: Diffie-Hellman support.
2132  */
2133 
2134 void
_libssh2_dh_init(_libssh2_dh_ctx * dhctx)2135 _libssh2_dh_init(_libssh2_dh_ctx *dhctx)
2136 {
2137     *dhctx = _libssh2_wincng_bignum_init();     /* Random from client */
2138 }
2139 
2140 int
_libssh2_dh_key_pair(_libssh2_dh_ctx * dhctx,_libssh2_bn * public,_libssh2_bn * g,_libssh2_bn * p,int group_order)2141 _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
2142                      _libssh2_bn *g, _libssh2_bn *p, int group_order)
2143 {
2144     /* Generate x and e */
2145     if(_libssh2_wincng_bignum_rand(*dhctx, group_order * 8 - 1, 0, -1))
2146         return -1;
2147     if(_libssh2_wincng_bignum_mod_exp(public, g, *dhctx, p))
2148         return -1;
2149     return 0;
2150 }
2151 
2152 int
_libssh2_dh_secret(_libssh2_dh_ctx * dhctx,_libssh2_bn * secret,_libssh2_bn * f,_libssh2_bn * p)2153 _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
2154                    _libssh2_bn *f, _libssh2_bn *p)
2155 {
2156     /* Compute the shared secret */
2157     _libssh2_wincng_bignum_mod_exp(secret, f, *dhctx, p);
2158     return 0;
2159 }
2160 
2161 void
_libssh2_dh_dtor(_libssh2_dh_ctx * dhctx)2162 _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
2163 {
2164     _libssh2_wincng_bignum_free(*dhctx);
2165     *dhctx = NULL;
2166 }
2167 
2168 #endif /* LIBSSH2_WINCNG */
2169