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