1 /*
2
3 silcpk.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 1997 - 2007 Pekka Riikonen
8
9 The contents of this file are subject to one of the Licenses specified
10 in the COPYING file; You may not use this file except in compliance
11 with the License.
12
13 The software distributed under the License is distributed on an "AS IS"
14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15 KIND, either expressed or implied. See the COPYING file for more
16 information.
17
18 */
19
20 #include "silc.h"
21 #include "silcpk_i.h"
22
23 /****************************** Key generation *******************************/
24
25 /* Generate new SILC key pair. */
26
silc_pkcs_silc_generate_key(const char * algorithm,SilcUInt32 bits_key_len,const char * identifier,SilcRng rng,SilcPublicKey * ret_public_key,SilcPrivateKey * ret_private_key)27 SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
28 SilcUInt32 bits_key_len,
29 const char *identifier,
30 SilcRng rng,
31 SilcPublicKey *ret_public_key,
32 SilcPrivateKey *ret_private_key)
33 {
34 SilcSILCPublicKey pubkey;
35 SilcSILCPrivateKey privkey;
36 const SilcPKCSAlgorithm *alg;
37 const SilcPKCSObject *pkcs;
38 SilcUInt32 version;
39
40 SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits",
41 algorithm, bits_key_len));
42
43 if (!rng)
44 return FALSE;
45
46 pkcs = silc_pkcs_find_pkcs(SILC_PKCS_SILC);
47 if (!pkcs)
48 return FALSE;
49
50 /* Allocate SILC public key */
51 pubkey = silc_calloc(1, sizeof(*pubkey));
52 if (!pubkey)
53 return FALSE;
54
55 /* Decode identifier */
56 if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier))
57 return FALSE;
58
59 if (pubkey->identifier.version && atoi(pubkey->identifier.version) >= 2)
60 version = 2;
61 else
62 version = 1;
63
64 /* Allocate algorithm */
65 alg = silc_pkcs_find_algorithm(algorithm, (version == 1 ? "pkcs1-no-oid" :
66 "pkcs1"));
67 if (!alg) {
68 silc_free(pubkey);
69 return FALSE;
70 }
71 pubkey->pkcs = alg;
72
73 /* Allocate SILC private key */
74 privkey = silc_calloc(1, sizeof(*privkey));
75 if (!privkey) {
76 silc_free(pubkey);
77 return FALSE;
78 }
79 privkey->pkcs = alg;
80
81 /* Allocate public key */
82 *ret_public_key = silc_calloc(1, sizeof(**ret_public_key));
83 if (!(*ret_public_key)) {
84 silc_free(pubkey);
85 silc_free(privkey);
86 return FALSE;
87 }
88 (*ret_public_key)->pkcs = pkcs;
89 (*ret_public_key)->public_key = pubkey;
90
91 /* Allocate private key */
92 *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
93 if (!(*ret_private_key)) {
94 silc_free(pubkey);
95 silc_free(privkey);
96 silc_free(*ret_public_key);
97 return FALSE;
98 }
99 (*ret_private_key)->pkcs = pkcs;
100 (*ret_private_key)->private_key = privkey;
101
102 /* Generate the algorithm key pair */
103 if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
104 &privkey->private_key)) {
105 silc_free(pubkey);
106 silc_free(privkey);
107 silc_free(*ret_public_key);
108 silc_free(*ret_private_key);
109 return FALSE;
110 }
111
112 return TRUE;
113 }
114
115
116 /**************************** Utility functions ******************************/
117
118 /* Decodes the provided `identifier' */
119
silc_pkcs_silc_decode_identifier(const char * identifier,SilcPublicKeyIdentifier ident)120 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
121 SilcPublicKeyIdentifier ident)
122 {
123 char *cp, *item;
124 int len;
125
126 /* Protocol says that at least UN and HN must be provided as identifier */
127 if (!strstr(identifier, "UN=") || !strstr(identifier, "HN=")) {
128 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
129 "identifiers"));
130 return FALSE;
131 }
132
133 cp = (char *)identifier;
134 while (cp) {
135 len = strcspn(cp, ",");
136 if (len < 1) {
137 cp = NULL;
138 break;
139 }
140 if (len - 1 >= 0 && cp[len - 1] == '\\') {
141 while (cp) {
142 if (len + 1 > strlen(cp)) {
143 cp = NULL;
144 break;
145 }
146 cp += len + 1;
147 len = strcspn(cp, ",") + len;
148 if (len < 1) {
149 cp = NULL;
150 break;
151 }
152 if (len - 1 >= 0 && cp[len - 1] != '\\')
153 break;
154 }
155 }
156
157 if (!cp)
158 break;
159
160 item = silc_calloc(len + 1, sizeof(char));
161 if (!item)
162 return FALSE;
163 if (len > strlen(cp))
164 break;
165 memcpy(item, cp, len);
166
167 if (strstr(item, "UN="))
168 ident->username = strdup(item + strcspn(cp, "=") + 1);
169 else if (strstr(item, "HN="))
170 ident->host = strdup(item + strcspn(cp, "=") + 1);
171 else if (strstr(item, "RN="))
172 ident->realname = strdup(item + strcspn(cp, "=") + 1);
173 else if (strstr(item, "E="))
174 ident->email = strdup(item + strcspn(cp, "=") + 1);
175 else if (strstr(item, "O="))
176 ident->org = strdup(item + strcspn(cp, "=") + 1);
177 else if (strstr(item, "C="))
178 ident->country = strdup(item + strcspn(cp, "=") + 1);
179 else if (strstr(item, "V="))
180 ident->version = strdup(item + strcspn(cp, "=") + 1);
181
182 cp += len;
183 if (strlen(cp) < 1)
184 cp = NULL;
185 else
186 cp += 1;
187
188 if (item)
189 silc_free(item);
190 }
191
192 return TRUE;
193 }
194
195 /* Encodes and returns SILC public key identifier. If some of the
196 arguments is NULL those are not encoded into the identifier string.
197 Protocol says that at least username and host must be provided. */
198
silc_pkcs_silc_encode_identifier(char * username,char * host,char * realname,char * email,char * org,char * country,char * version)199 char *silc_pkcs_silc_encode_identifier(char *username, char *host,
200 char *realname, char *email,
201 char *org, char *country,
202 char *version)
203 {
204 SilcBufferStruct buf;
205 char *identifier;
206
207 if (!username || !host)
208 return NULL;
209 if (strlen(username) < 1 || strlen(host) < 1)
210 return NULL;
211
212 memset(&buf, 0, sizeof(buf));
213
214 if (username)
215 silc_buffer_format(&buf,
216 SILC_STR_ADVANCE,
217 SILC_STR_UI32_STRING("UN="),
218 SILC_STR_UI32_STRING(username),
219 SILC_STR_END);
220
221 if (host)
222 silc_buffer_format(&buf,
223 SILC_STR_ADVANCE,
224 SILC_STR_UI32_STRING(", "),
225 SILC_STR_UI32_STRING("HN="),
226 SILC_STR_UI32_STRING(host),
227 SILC_STR_END);
228
229 if (realname)
230 silc_buffer_format(&buf,
231 SILC_STR_ADVANCE,
232 SILC_STR_UI32_STRING(", "),
233 SILC_STR_UI32_STRING("RN="),
234 SILC_STR_UI32_STRING(realname),
235 SILC_STR_END);
236
237 if (email)
238 silc_buffer_format(&buf,
239 SILC_STR_ADVANCE,
240 SILC_STR_UI32_STRING(", "),
241 SILC_STR_UI32_STRING("E="),
242 SILC_STR_UI32_STRING(email),
243 SILC_STR_END);
244
245 if (org)
246 silc_buffer_format(&buf,
247 SILC_STR_ADVANCE,
248 SILC_STR_UI32_STRING(", "),
249 SILC_STR_UI32_STRING("O="),
250 SILC_STR_UI32_STRING(org),
251 SILC_STR_END);
252
253 if (country)
254 silc_buffer_format(&buf,
255 SILC_STR_ADVANCE,
256 SILC_STR_UI32_STRING(", "),
257 SILC_STR_UI32_STRING("C="),
258 SILC_STR_UI32_STRING(country),
259 SILC_STR_END);
260
261 if (version) {
262 if (strlen(version) > 1 || !isdigit(version[0])) {
263 silc_buffer_purge(&buf);
264 return NULL;
265 }
266 silc_buffer_format(&buf,
267 SILC_STR_ADVANCE,
268 SILC_STR_UI32_STRING(", "),
269 SILC_STR_UI32_STRING("V="),
270 SILC_STR_UI32_STRING(version),
271 SILC_STR_END);
272 }
273
274 silc_buffer_format(&buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
275
276 identifier = silc_buffer_steal(&buf, NULL);
277 return identifier;
278 }
279
280 /* Return SILC public key version */
281
silc_pkcs_silc_public_key_version(SilcPublicKey public_key)282 int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
283 {
284 SilcSILCPublicKey silc_pubkey;
285
286 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
287 return -1;
288
289 silc_pubkey = public_key->public_key;
290
291 /* If version identifire is not present it is version 1. */
292 if (!silc_pubkey->identifier.version)
293 return 1;
294
295 return atoi(silc_pubkey->identifier.version);
296 }
297
298 /*************************** Public key routines *****************************/
299
300 /* Returns PKCS algorithm context */
301
silc_pkcs_silc_get_algorithm(void * public_key)302 const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
303 {
304 SilcSILCPublicKey silc_pubkey = public_key;
305 return silc_pubkey->pkcs;
306 }
307
308 /* Imports SILC protocol style public key from SILC public key file */
309
silc_pkcs_silc_import_public_key_file(unsigned char * filedata,SilcUInt32 filedata_len,SilcPKCSFileEncoding encoding,void ** ret_public_key)310 SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
311 SilcUInt32 filedata_len,
312 SilcPKCSFileEncoding encoding,
313 void **ret_public_key)
314 {
315 SilcUInt32 i, len;
316 unsigned char *data = NULL;
317 int ret;
318
319 SILC_LOG_DEBUG(("Parsing SILC public key file"));
320
321 if (!ret_public_key)
322 return FALSE;
323
324 /* Check start of file and remove header from the data. */
325 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
326 if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)) {
327 SILC_LOG_ERROR(("Malformed SILC public key header"));
328 return FALSE;
329 }
330 for (i = 0; i < len; i++) {
331 if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
332 SILC_LOG_ERROR(("Malformed SILC public key header"));
333 return FALSE;
334 }
335 filedata++;
336 }
337 filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
338 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
339
340 switch (encoding) {
341 case SILC_PKCS_FILE_BIN:
342 break;
343
344 case SILC_PKCS_FILE_BASE64:
345 data = silc_base64_decode(filedata, filedata_len, &filedata_len);
346 if (!data)
347 return FALSE;
348 filedata = data;
349 break;
350 }
351
352 ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
353 ret_public_key);
354 silc_free(data);
355
356 return ret ? TRUE : FALSE;
357 }
358
359 /* Imports SILC protocol style public key */
360
silc_pkcs_silc_import_public_key(unsigned char * key,SilcUInt32 key_len,void ** ret_public_key)361 int silc_pkcs_silc_import_public_key(unsigned char *key,
362 SilcUInt32 key_len,
363 void **ret_public_key)
364 {
365 const SilcPKCSAlgorithm *pkcs;
366 SilcBufferStruct buf, alg_key;
367 SilcSILCPublicKey silc_pubkey = NULL;
368 SilcAsn1 asn1 = NULL;
369 SilcUInt32 totlen, keydata_len;
370 SilcUInt16 pkcs_len, identifier_len;
371 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
372 int ret;
373
374 SILC_LOG_DEBUG(("Parsing SILC public key"));
375
376 if (!ret_public_key)
377 return 0;
378
379 silc_buffer_set(&buf, key, key_len);
380
381 /* Get length */
382 ret = silc_buffer_unformat(&buf,
383 SILC_STR_ADVANCE,
384 SILC_STR_UI_INT(&totlen),
385 SILC_STR_END);
386 if (ret == -1)
387 goto err;
388
389 /* Backwards compatibility */
390 if (totlen == key_len)
391 totlen -= 4;
392
393 if (totlen + 4 != key_len)
394 goto err;
395
396 /* Get algorithm name and identifier */
397 ret =
398 silc_buffer_unformat(&buf,
399 SILC_STR_ADVANCE,
400 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
401 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
402 SILC_STR_END);
403 if (ret == -1)
404 goto err;
405
406 if (pkcs_len < 1 || identifier_len < 3 ||
407 pkcs_len + identifier_len > totlen)
408 goto err;
409
410 /* Get key data */
411 keydata_len = silc_buffer_len(&buf);
412 ret = silc_buffer_unformat(&buf,
413 SILC_STR_DATA(&key_data, keydata_len),
414 SILC_STR_END);
415 if (ret == -1)
416 goto err;
417
418 /* Allocate SILC public key context */
419 silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
420 if (!silc_pubkey)
421 goto err;
422
423 /* Decode SILC identifier */
424 if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
425 goto err;
426
427 asn1 = silc_asn1_alloc();
428 if (!asn1)
429 goto err;
430
431 SILC_LOG_DEBUG(("Public key version %s",
432 (!silc_pubkey->identifier.version ? "1" :
433 silc_pubkey->identifier.version)));
434
435 if (!strcmp(pkcs_name, "rsa")) {
436 /* Parse the SILC RSA public key */
437 SilcUInt32 e_len, n_len;
438 SilcMPInt n, e;
439
440 /* Get PKCS object. Different PKCS #1 scheme is used with different
441 versions. */
442 if (!silc_pubkey->identifier.version ||
443 atoi(silc_pubkey->identifier.version) <= 1) {
444 /* Version 1 */
445 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
446 } else {
447 /* Version 2 and newer */
448 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
449 }
450 if (!pkcs) {
451 SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa"));
452 goto err;
453 }
454 silc_pubkey->pkcs = pkcs;
455
456 if (keydata_len < 4)
457 goto err;
458 SILC_GET32_MSB(e_len, key_data);
459 if (!e_len || e_len + 4 > keydata_len)
460 goto err;
461 silc_mp_init(&e);
462 silc_mp_bin2mp(key_data + 4, e_len, &e);
463 if (keydata_len < 4 + e_len + 4) {
464 silc_mp_uninit(&e);
465 goto err;
466 }
467 SILC_GET32_MSB(n_len, key_data + 4 + e_len);
468 if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
469 silc_mp_uninit(&e);
470 goto err;
471 }
472 silc_mp_init(&n);
473 silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
474
475 /* Encode to PKCS #1 format */
476 memset(&alg_key, 0, sizeof(alg_key));
477 if (!silc_asn1_encode(asn1, &alg_key,
478 SILC_ASN1_SEQUENCE,
479 SILC_ASN1_INT(&n),
480 SILC_ASN1_INT(&e),
481 SILC_ASN1_END, SILC_ASN1_END)) {
482 silc_mp_uninit(&e);
483 silc_mp_uninit(&n);
484 goto err;
485 }
486
487 silc_mp_uninit(&e);
488 silc_mp_uninit(&n);
489
490 } else if (!strcmp(pkcs_name, "dsa")) {
491 SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
492 goto err;
493
494 } else {
495 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
496 goto err;
497 }
498
499 /* Import PKCS algorithm public key */
500 if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
501 &silc_pubkey->public_key))
502 goto err;
503
504 silc_free(pkcs_name);
505 silc_free(ident);
506 silc_asn1_free(asn1);
507
508 *ret_public_key = silc_pubkey;
509
510 return key_len;
511
512 err:
513 silc_free(pkcs_name);
514 silc_free(ident);
515 silc_free(silc_pubkey);
516 if (asn1)
517 silc_asn1_free(asn1);
518 return 0;
519 }
520
521 /* Exports public key as SILC protocol style public key file */
522
523 unsigned char *
silc_pkcs_silc_export_public_key_file(void * public_key,SilcPKCSFileEncoding encoding,SilcUInt32 * ret_len)524 silc_pkcs_silc_export_public_key_file(void *public_key,
525 SilcPKCSFileEncoding encoding,
526 SilcUInt32 *ret_len)
527 {
528 SilcBuffer buf;
529 unsigned char *key, *data;
530 SilcUInt32 key_len;
531
532 SILC_LOG_DEBUG(("Encoding SILC public key file"));
533
534 /* Export key */
535 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
536 if (!key)
537 return NULL;
538
539 switch (encoding) {
540 case SILC_PKCS_FILE_BIN:
541 break;
542
543 case SILC_PKCS_FILE_BASE64:
544 data = silc_base64_encode_file(key, key_len);
545 if (!data)
546 return NULL;
547 silc_free(key);
548 key = data;
549 key_len = strlen(data);
550 break;
551 }
552
553 /* Encode SILC public key file */
554 buf = silc_buffer_alloc_size(key_len +
555 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
556 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
557 if (!buf) {
558 silc_free(key);
559 return NULL;
560 }
561
562 if (silc_buffer_format(buf,
563 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
564 SILC_STR_UI_XNSTRING(key, key_len),
565 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
566 SILC_STR_END) < 0) {
567 silc_buffer_free(buf);
568 silc_free(key);
569 return NULL;
570 }
571
572 silc_free(key);
573 key = silc_buffer_steal(buf, ret_len);
574 silc_buffer_free(buf);
575
576 return key;
577 }
578
579 /* Exports public key as SILC protocol style public key */
580
silc_pkcs_silc_export_public_key(void * public_key,SilcUInt32 * ret_len)581 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
582 SilcUInt32 *ret_len)
583 {
584 SilcSILCPublicKey silc_pubkey = public_key;
585 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
586 SilcBufferStruct alg_key;
587 SilcBuffer buf = NULL;
588 SilcAsn1 asn1 = NULL;
589 unsigned char *pk = NULL, *key = NULL, *ret;
590 SilcUInt32 pk_len, key_len, totlen;
591 char *identifier;
592
593 SILC_LOG_DEBUG(("Encoding SILC public key"));
594
595 /* Export PKCS algorithm public key */
596 if (pkcs->export_public_key)
597 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
598 if (!pk) {
599 SILC_LOG_ERROR(("Error exporting PKCS algorithm key"));
600 return NULL;
601 }
602 silc_buffer_set(&alg_key, pk, pk_len);
603
604 /* Encode identifier */
605 identifier =
606 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
607 silc_pubkey->identifier.host,
608 silc_pubkey->identifier.realname,
609 silc_pubkey->identifier.email,
610 silc_pubkey->identifier.org,
611 silc_pubkey->identifier.country,
612 silc_pubkey->identifier.version);
613 if (!identifier) {
614 SILC_LOG_ERROR(("Error encoding SILC public key identifier"));
615 goto err;
616 }
617
618 asn1 = silc_asn1_alloc();
619 if (!asn1)
620 goto err;
621
622 if (!strcmp(pkcs->name, "rsa")) {
623 /* Parse the PKCS #1 public key */
624 SilcMPInt n, e;
625 SilcUInt32 n_len, e_len;
626 unsigned char *nb, *eb;
627
628 memset(&n, 0, sizeof(n));
629 memset(&e, 0, sizeof(e));
630 if (!silc_asn1_decode(asn1, &alg_key,
631 SILC_ASN1_SEQUENCE,
632 SILC_ASN1_INT(&n),
633 SILC_ASN1_INT(&e),
634 SILC_ASN1_END, SILC_ASN1_END))
635 goto err;
636
637 /* Encode to SILC RSA public key */
638 eb = silc_mp_mp2bin(&e, 0, &e_len);
639 if (!eb)
640 goto err;
641 nb = silc_mp_mp2bin(&n, 0, &n_len);
642 if (!nb)
643 goto err;
644 key_len = e_len + 4 + n_len + 4;
645 key = silc_calloc(key_len, sizeof(*key));
646 if (!key)
647 goto err;
648
649 /* Put e length and e */
650 SILC_PUT32_MSB(e_len, key);
651 memcpy(key + 4, eb, e_len);
652
653 /* Put n length and n. */
654 SILC_PUT32_MSB(n_len, key + 4 + e_len);
655 memcpy(key + 4 + e_len + 4, nb, n_len);
656
657 silc_free(nb);
658 silc_free(eb);
659
660 } else if (!strcmp(pkcs->name, "dsa")) {
661 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
662 goto err;
663
664 } else {
665 SILC_LOG_ERROR(("Unsupported PKCS algorithm: %s", pkcs->name));
666 goto err;
667 }
668
669 /* Encode SILC Public Key */
670 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
671 buf = silc_buffer_alloc_size(totlen + 4);
672 if (!buf)
673 goto err;
674 if (silc_buffer_format(buf,
675 SILC_STR_UI_INT(totlen),
676 SILC_STR_UI_SHORT(strlen(pkcs->name)),
677 SILC_STR_UI32_STRING(pkcs->name),
678 SILC_STR_UI_SHORT(strlen(identifier)),
679 SILC_STR_UI32_STRING(identifier),
680 SILC_STR_UI_XNSTRING(key, key_len),
681 SILC_STR_END) < 0)
682 goto err;
683
684 ret = silc_buffer_steal(buf, ret_len);
685 silc_buffer_free(buf);
686 silc_free(key);
687 silc_free(identifier);
688 silc_buffer_purge(&alg_key);
689 silc_asn1_free(asn1);
690
691 return ret;
692
693 err:
694 silc_free(identifier);
695 silc_free(pk);
696 silc_free(key);
697 if (buf)
698 silc_buffer_free(buf);
699 if (asn1)
700 silc_asn1_free(asn1);
701 return NULL;
702 }
703
704 /* Return key length */
705
silc_pkcs_silc_public_key_bitlen(void * public_key)706 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
707 {
708 SilcSILCPublicKey silc_pubkey = public_key;
709 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
710 }
711
712 /* Copy public key */
713
silc_pkcs_silc_public_key_copy(void * public_key)714 void *silc_pkcs_silc_public_key_copy(void *public_key)
715 {
716 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
717 SilcPublicKeyIdentifier ident = &silc_pubkey->identifier;
718
719 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
720 if (!new_pubkey)
721 return NULL;
722 new_pubkey->pkcs = silc_pubkey->pkcs;
723
724 new_pubkey->public_key =
725 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
726 if (!new_pubkey->public_key) {
727 silc_free(new_pubkey);
728 return NULL;
729 }
730
731 if (ident->username)
732 new_pubkey->identifier.username =
733 silc_memdup(ident->username, strlen(ident->username));
734 if (ident->host)
735 new_pubkey->identifier.host =
736 silc_memdup(ident->host, strlen(ident->host));
737 if (ident->realname)
738 new_pubkey->identifier.realname =
739 silc_memdup(ident->realname, strlen(ident->realname));
740 if (ident->email)
741 new_pubkey->identifier.email =
742 silc_memdup(ident->email, strlen(ident->email));
743 if (ident->org)
744 new_pubkey->identifier.org =
745 silc_memdup(ident->org, strlen(ident->org));
746 if (ident->country)
747 new_pubkey->identifier.country =
748 silc_memdup(ident->country, strlen(ident->country));
749 if (ident->version)
750 new_pubkey->identifier.version =
751 silc_memdup(ident->version, strlen(ident->version));
752
753 return new_pubkey;
754 }
755
756 /* Compares public keys */
757
silc_pkcs_silc_public_key_compare(void * key1,void * key2)758 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
759 {
760 SilcSILCPublicKey k1 = key1, k2 = key2;
761
762 if (strcmp(k1->pkcs->name, k2->pkcs->name))
763 return FALSE;
764
765 if ((k1->identifier.username && !k2->identifier.username) ||
766 (!k1->identifier.username && k2->identifier.username) ||
767 (k1->identifier.username && k2->identifier.username &&
768 strcmp(k1->identifier.username, k2->identifier.username)))
769 return FALSE;
770
771 if ((k1->identifier.host && !k2->identifier.host) ||
772 (!k1->identifier.host && k2->identifier.host) ||
773 (k1->identifier.host && k2->identifier.host &&
774 strcmp(k1->identifier.host, k2->identifier.host)))
775 return FALSE;
776
777 if ((k1->identifier.realname && !k2->identifier.realname) ||
778 (!k1->identifier.realname && k2->identifier.realname) ||
779 (k1->identifier.realname && k2->identifier.realname &&
780 strcmp(k1->identifier.realname, k2->identifier.realname)))
781 return FALSE;
782
783 if ((k1->identifier.email && !k2->identifier.email) ||
784 (!k1->identifier.email && k2->identifier.email) ||
785 (k1->identifier.email && k2->identifier.email &&
786 strcmp(k1->identifier.email, k2->identifier.email)))
787 return FALSE;
788
789 if ((k1->identifier.org && !k2->identifier.org) ||
790 (!k1->identifier.org && k2->identifier.org) ||
791 (k1->identifier.org && k2->identifier.org &&
792 strcmp(k1->identifier.org, k2->identifier.org)))
793 return FALSE;
794
795 if ((k1->identifier.country && !k2->identifier.country) ||
796 (!k1->identifier.country && k2->identifier.country) ||
797 (k1->identifier.country && k2->identifier.country &&
798 strcmp(k1->identifier.country, k2->identifier.country)))
799 return FALSE;
800
801 if ((k1->identifier.version && !k2->identifier.version) ||
802 (!k1->identifier.version && k2->identifier.version) ||
803 (k1->identifier.version && k2->identifier.version &&
804 strcmp(k1->identifier.version, k2->identifier.version)))
805 return FALSE;
806
807 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
808 }
809
810 /* Frees public key */
811
silc_pkcs_silc_public_key_free(void * public_key)812 void silc_pkcs_silc_public_key_free(void *public_key)
813 {
814 SilcSILCPublicKey silc_pubkey = public_key;
815
816 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
817
818 silc_free(silc_pubkey->identifier.username);
819 silc_free(silc_pubkey->identifier.host);
820 silc_free(silc_pubkey->identifier.realname);
821 silc_free(silc_pubkey->identifier.email);
822 silc_free(silc_pubkey->identifier.org);
823 silc_free(silc_pubkey->identifier.country);
824 silc_free(silc_pubkey->identifier.version);
825 silc_free(silc_pubkey);
826 }
827
828
829 /*************************** Private key routines ****************************/
830
831 /* Private key file magic */
832 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
833
834 /* Imports SILC implementation style private key file */
835
silc_pkcs_silc_import_private_key_file(unsigned char * filedata,SilcUInt32 filedata_len,const char * passphrase,SilcUInt32 passphrase_len,SilcPKCSFileEncoding encoding,void ** ret_private_key)836 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
837 SilcUInt32 filedata_len,
838 const char *passphrase,
839 SilcUInt32 passphrase_len,
840 SilcPKCSFileEncoding encoding,
841 void **ret_private_key)
842 {
843 SilcCipher aes;
844 SilcHash sha1;
845 SilcHmac sha1hmac;
846 SilcUInt32 blocklen;
847 unsigned char tmp[32], keymat[64], *data = NULL;
848 SilcUInt32 i, len, magic, mac_len;
849 int ret;
850
851 SILC_LOG_DEBUG(("Parsing SILC private key file"));
852
853 /* Check start of file and remove header from the data. */
854 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
855 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) {
856 SILC_LOG_ERROR(("Malformed SILC private key header"));
857 return FALSE;
858 }
859 for (i = 0; i < len; i++) {
860 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
861 SILC_LOG_ERROR(("Malformed SILC private key header"));
862 return FALSE;
863 }
864 filedata++;
865 }
866
867 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
868 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
869
870 switch (encoding) {
871 case SILC_PKCS_FILE_BIN:
872 break;
873
874 case SILC_PKCS_FILE_BASE64:
875 data = silc_base64_decode(filedata, filedata_len, &len);
876 if (!data)
877 return FALSE;
878 filedata = data;
879 break;
880 }
881
882 memset(tmp, 0, sizeof(tmp));
883 memset(keymat, 0, sizeof(keymat));
884
885 /* Check file magic */
886 SILC_GET32_MSB(magic, filedata);
887 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
888 SILC_LOG_DEBUG(("Private key does not have correct magic"));
889 return FALSE;
890 }
891
892 /* Allocate the AES cipher */
893 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
894 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
895 return FALSE;
896 }
897 blocklen = silc_cipher_get_block_len(aes);
898 if (blocklen * 2 > sizeof(tmp)) {
899 silc_cipher_free(aes);
900 return FALSE;
901 }
902
903 /* Allocate SHA1 hash */
904 if (!silc_hash_alloc("sha1", &sha1)) {
905 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
906 silc_cipher_free(aes);
907 return FALSE;
908 }
909
910 /* Allocate HMAC */
911 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
912 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
913 silc_hash_free(sha1);
914 silc_cipher_free(aes);
915 return FALSE;
916 }
917
918 /* Derive the decryption key from the provided key material. The key
919 is 256 bits length, and derived by taking hash of the data, then
920 re-hashing the data and the previous digest, and using the first and
921 second digest as the key. */
922 silc_hash_init(sha1);
923 silc_hash_update(sha1, passphrase, passphrase_len);
924 silc_hash_final(sha1, keymat);
925 silc_hash_init(sha1);
926 silc_hash_update(sha1, passphrase, passphrase_len);
927 silc_hash_update(sha1, keymat, 16);
928 silc_hash_final(sha1, keymat + 16);
929
930 /* Set the key to the cipher */
931 silc_cipher_set_key(aes, keymat, 256, FALSE);
932
933 /* First, verify the MAC of the private key data */
934 mac_len = silc_hmac_len(sha1hmac);
935 silc_hmac_init_with_key(sha1hmac, keymat, 16);
936 silc_hmac_update(sha1hmac, filedata, len - mac_len);
937 silc_hmac_final(sha1hmac, tmp, NULL);
938 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
939 SILC_LOG_DEBUG(("Integrity check for private key failed"));
940 memset(keymat, 0, sizeof(keymat));
941 memset(tmp, 0, sizeof(tmp));
942 silc_hmac_free(sha1hmac);
943 silc_hash_free(sha1);
944 silc_cipher_free(aes);
945 return FALSE;
946 }
947 filedata += 4;
948 len -= 4;
949
950 /* Decrypt the private key buffer */
951 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
952 SILC_GET32_MSB(i, filedata);
953 if (i > len) {
954 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
955 memset(keymat, 0, sizeof(keymat));
956 memset(tmp, 0, sizeof(tmp));
957 silc_hmac_free(sha1hmac);
958 silc_hash_free(sha1);
959 silc_cipher_free(aes);
960 return FALSE;
961 }
962 filedata += 4;
963 len = i;
964
965 /* Cleanup */
966 memset(keymat, 0, sizeof(keymat));
967 memset(tmp, 0, sizeof(tmp));
968 silc_hmac_free(sha1hmac);
969 silc_hash_free(sha1);
970 silc_cipher_free(aes);
971
972 /* Import the private key */
973 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
974
975 silc_free(data);
976
977 return ret ? TRUE : FALSE;
978 }
979
980 /* Private key version */
981 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
982 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
983
984 /* Imports SILC implementation style private key */
985
silc_pkcs_silc_import_private_key(unsigned char * key,SilcUInt32 key_len,void ** ret_private_key)986 int silc_pkcs_silc_import_private_key(unsigned char *key,
987 SilcUInt32 key_len,
988 void **ret_private_key)
989 {
990 SilcBufferStruct buf;
991 const SilcPKCSAlgorithm *pkcs;
992 SilcBufferStruct alg_key;
993 SilcSILCPrivateKey silc_privkey = NULL;
994 SilcAsn1 asn1 = NULL;
995 SilcUInt16 pkcs_len;
996 SilcUInt32 keydata_len;
997 unsigned char *pkcs_name = NULL, *key_data;
998 int ret;
999
1000 SILC_LOG_DEBUG(("Parsing SILC private key"));
1001
1002 if (!ret_private_key)
1003 return 0;
1004
1005 silc_buffer_set(&buf, key, key_len);
1006
1007 /* Get algorithm name and identifier */
1008 ret =
1009 silc_buffer_unformat(&buf,
1010 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1011 SILC_STR_END);
1012 if (ret == -1) {
1013 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1014 goto err;
1015 }
1016
1017 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
1018 SILC_LOG_DEBUG(("Malformed private key buffer"));
1019 goto err;
1020 }
1021
1022 /* Get key data. We assume that rest of the buffer is key data. */
1023 silc_buffer_pull(&buf, 2 + pkcs_len);
1024 keydata_len = silc_buffer_len(&buf);
1025 ret = silc_buffer_unformat(&buf,
1026 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
1027 SILC_STR_END);
1028 if (ret == -1)
1029 goto err;
1030
1031 /* Allocate SILC private key context */
1032 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
1033 if (!silc_privkey)
1034 goto err;
1035
1036 asn1 = silc_asn1_alloc();
1037 if (!asn1)
1038 goto err;
1039
1040 if (!strcmp(pkcs_name, "rsa")) {
1041 /* Parse the RSA SILC private key */
1042 SilcBufferStruct k;
1043 SilcMPInt n, e, d, dp, dq, qp, p, q;
1044 unsigned char *tmp;
1045 SilcUInt32 len, ver;
1046
1047 if (keydata_len < 4)
1048 goto err;
1049 silc_buffer_set(&k, key_data, keydata_len);
1050
1051 /* Get version. Key without the version is old style private key
1052 and we need to do some computation to get it to correct format. */
1053 if (silc_buffer_unformat(&k,
1054 SILC_STR_UI_INT(&ver),
1055 SILC_STR_END) < 0)
1056 goto err;
1057 silc_buffer_pull(&k, 4);
1058
1059 if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1060 ver != SILC_PRIVATE_KEY_VERSION_2) {
1061 len = ver;
1062 ver = 0;
1063 } else {
1064 if (silc_buffer_unformat(&k,
1065 SILC_STR_UI_INT(&len),
1066 SILC_STR_END) < 0)
1067 goto err;
1068 silc_buffer_pull(&k, 4);
1069 }
1070
1071 /* Get PKCS object. Different PKCS #1 scheme is used with different
1072 versions. */
1073 if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1074 /* Version 0 and 1 */
1075 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1076 } else {
1077 /* Version 2 and newer */
1078 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1079 }
1080 if (!pkcs) {
1081 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1082 goto err;
1083 }
1084 silc_privkey->pkcs = pkcs;
1085
1086 SILC_LOG_DEBUG(("Private key version %s",
1087 (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1088 ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1089
1090 /* Get e */
1091 if (silc_buffer_unformat(&k,
1092 SILC_STR_DATA(&tmp, len),
1093 SILC_STR_END) < 0)
1094 goto err;
1095 silc_mp_init(&e);
1096 silc_mp_bin2mp(tmp, len, &e);
1097 silc_buffer_pull(&k, len);
1098
1099 /* Get n */
1100 if (silc_buffer_unformat(&k,
1101 SILC_STR_UI_INT(&len),
1102 SILC_STR_END) < 0)
1103 goto err;
1104 silc_buffer_pull(&k, 4);
1105 if (silc_buffer_unformat(&k,
1106 SILC_STR_DATA(&tmp, len),
1107 SILC_STR_END) < 0)
1108 goto err;
1109 silc_mp_init(&n);
1110 silc_mp_bin2mp(tmp, len, &n);
1111 silc_buffer_pull(&k, len);
1112
1113 /* Get d */
1114 if (silc_buffer_unformat(&k,
1115 SILC_STR_UI_INT(&len),
1116 SILC_STR_END) < 0)
1117 goto err;
1118 silc_buffer_pull(&k, 4);
1119 if (silc_buffer_unformat(&k,
1120 SILC_STR_DATA(&tmp, len),
1121 SILC_STR_END) < 0)
1122 goto err;
1123 silc_mp_init(&d);
1124 silc_mp_bin2mp(tmp, len, &d);
1125 silc_buffer_pull(&k, len);
1126
1127 /* Get dP */
1128 if (silc_buffer_unformat(&k,
1129 SILC_STR_UI_INT(&len),
1130 SILC_STR_END) < 0)
1131 goto err;
1132 silc_buffer_pull(&k, 4);
1133 if (silc_buffer_unformat(&k,
1134 SILC_STR_DATA(&tmp, len),
1135 SILC_STR_END) < 0)
1136 goto err;
1137 silc_mp_init(&dp);
1138 silc_mp_bin2mp(tmp, len, &dp);
1139 silc_buffer_pull(&k, len);
1140
1141 /* Get dQ */
1142 if (silc_buffer_unformat(&k,
1143 SILC_STR_UI_INT(&len),
1144 SILC_STR_END) < 0)
1145 goto err;
1146 silc_buffer_pull(&k, 4);
1147 if (silc_buffer_unformat(&k,
1148 SILC_STR_DATA(&tmp, len),
1149 SILC_STR_END) < 0)
1150 goto err;
1151 silc_mp_init(&dq);
1152 silc_mp_bin2mp(tmp, len, &dq);
1153 silc_buffer_pull(&k, len);
1154
1155 if (ver == 0) {
1156 /* Old version */
1157
1158 /* Get pQ len */
1159 if (silc_buffer_unformat(&k,
1160 SILC_STR_UI_INT(&len),
1161 SILC_STR_END) < 0)
1162 goto err;
1163 silc_buffer_pull(&k, 4);
1164 if (silc_buffer_len(&k) < len)
1165 goto err;
1166 silc_buffer_pull(&k, len);
1167
1168 /* Get qP len */
1169 if (silc_buffer_unformat(&k,
1170 SILC_STR_UI_INT(&len),
1171 SILC_STR_END) < 0)
1172 goto err;
1173 silc_buffer_pull(&k, 4);
1174 if (silc_buffer_len(&k) < len)
1175 goto err;
1176 silc_buffer_pull(&k, len);
1177 } else {
1178 /* New version */
1179
1180 /* Get qP */
1181 if (silc_buffer_unformat(&k,
1182 SILC_STR_UI_INT(&len),
1183 SILC_STR_END) < 0)
1184 goto err;
1185 silc_buffer_pull(&k, 4);
1186 if (silc_buffer_unformat(&k,
1187 SILC_STR_DATA(&tmp, len),
1188 SILC_STR_END) < 0)
1189 goto err;
1190 silc_mp_init(&qp);
1191 silc_mp_bin2mp(tmp, len, &qp);
1192 silc_buffer_pull(&k, len);
1193 }
1194
1195 /* Get p */
1196 if (silc_buffer_unformat(&k,
1197 SILC_STR_UI_INT(&len),
1198 SILC_STR_END) < 0)
1199 goto err;
1200 silc_buffer_pull(&k, 4);
1201 if (silc_buffer_unformat(&k,
1202 SILC_STR_DATA(&tmp, len),
1203 SILC_STR_END) < 0)
1204 goto err;
1205 silc_mp_init(&p);
1206 silc_mp_bin2mp(tmp, len, &p);
1207 silc_buffer_pull(&k, len);
1208
1209 /* Get q */
1210 if (silc_buffer_unformat(&k,
1211 SILC_STR_UI_INT(&len),
1212 SILC_STR_END) < 0)
1213 goto err;
1214 silc_buffer_pull(&k, 4);
1215 if (silc_buffer_unformat(&k,
1216 SILC_STR_DATA(&tmp, len),
1217 SILC_STR_END) < 0)
1218 goto err;
1219 silc_mp_init(&q);
1220 silc_mp_bin2mp(tmp, len, &q);
1221 silc_buffer_pull(&k, len);
1222
1223 if (ver == 0) {
1224 /* Old version. Compute to new version */
1225 SILC_LOG_DEBUG(("Old version private key"));
1226 silc_mp_init(&qp);
1227 silc_mp_modinv(&qp, &q, &p);
1228 }
1229
1230 /* Encode to PKCS #1 format */
1231 memset(&alg_key, 0, sizeof(alg_key));
1232 if (!silc_asn1_encode(asn1, &alg_key,
1233 SILC_ASN1_SEQUENCE,
1234 SILC_ASN1_SHORT_INT(0),
1235 SILC_ASN1_INT(&n),
1236 SILC_ASN1_INT(&e),
1237 SILC_ASN1_INT(&d),
1238 SILC_ASN1_INT(&p),
1239 SILC_ASN1_INT(&q),
1240 SILC_ASN1_INT(&dp),
1241 SILC_ASN1_INT(&dq),
1242 SILC_ASN1_INT(&qp),
1243 SILC_ASN1_END, SILC_ASN1_END))
1244 goto err;
1245
1246 silc_mp_uninit(&n);
1247 silc_mp_uninit(&e);
1248 silc_mp_uninit(&e);
1249 silc_mp_uninit(&d);
1250 silc_mp_uninit(&p);
1251 silc_mp_uninit(&q);
1252 silc_mp_uninit(&dp);
1253 silc_mp_uninit(&dq);
1254 silc_mp_uninit(&qp);
1255
1256 } else if (!strcmp(pkcs_name, "dsa")) {
1257 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1258 goto err;
1259
1260 } else {
1261 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1262 goto err;
1263 }
1264
1265 /* Import PKCS algorithm private key */
1266 if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1267 &silc_privkey->private_key))
1268 goto err;
1269
1270 silc_free(pkcs_name);
1271 silc_asn1_free(asn1);
1272
1273 *ret_private_key = silc_privkey;
1274
1275 return key_len;
1276
1277 err:
1278 silc_free(pkcs_name);
1279 silc_free(silc_privkey);
1280 if (asn1)
1281 silc_asn1_free(asn1);
1282 SILC_LOG_ERROR(("Malformed SILC private key "));
1283 return 0;
1284 }
1285
1286 /* Exports private key as SILC implementation style private key file */
1287
1288 unsigned char *
silc_pkcs_silc_export_private_key_file(void * private_key,const char * passphrase,SilcUInt32 passphrase_len,SilcPKCSFileEncoding encoding,SilcRng rng,SilcUInt32 * ret_len)1289 silc_pkcs_silc_export_private_key_file(void *private_key,
1290 const char *passphrase,
1291 SilcUInt32 passphrase_len,
1292 SilcPKCSFileEncoding encoding,
1293 SilcRng rng,
1294 SilcUInt32 *ret_len)
1295 {
1296 SilcCipher aes;
1297 SilcHash sha1;
1298 SilcHmac sha1hmac;
1299 SilcBuffer buf, enc;
1300 SilcUInt32 len, blocklen, padlen, key_len;
1301 unsigned char *key, *data;
1302 unsigned char tmp[32], keymat[64];
1303 int i;
1304
1305 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1306
1307 /* Export the private key */
1308 key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1309 if (!key)
1310 return NULL;
1311
1312 memset(tmp, 0, sizeof(tmp));
1313 memset(keymat, 0, sizeof(keymat));
1314
1315 /* Allocate the AES cipher */
1316 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1317 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1318 silc_free(key);
1319 return NULL;
1320 }
1321 blocklen = silc_cipher_get_block_len(aes);
1322 if (blocklen * 2 > sizeof(tmp)) {
1323 silc_cipher_free(aes);
1324 silc_free(key);
1325 return NULL;
1326 }
1327
1328 /* Allocate SHA1 hash */
1329 if (!silc_hash_alloc("sha1", &sha1)) {
1330 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1331 silc_cipher_free(aes);
1332 return NULL;
1333 }
1334
1335 /* Allocate HMAC */
1336 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1337 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1338 silc_hash_free(sha1);
1339 silc_cipher_free(aes);
1340 return NULL;
1341 }
1342
1343 /* Derive the encryption key from the provided key material. The key
1344 is 256 bits length, and derived by taking hash of the data, then
1345 re-hashing the data and the previous digest, and using the first and
1346 second digest as the key. */
1347 silc_hash_init(sha1);
1348 silc_hash_update(sha1, passphrase, passphrase_len);
1349 silc_hash_final(sha1, keymat);
1350 silc_hash_init(sha1);
1351 silc_hash_update(sha1, passphrase, passphrase_len);
1352 silc_hash_update(sha1, keymat, 16);
1353 silc_hash_final(sha1, keymat + 16);
1354
1355 /* Set the key to the cipher */
1356 silc_cipher_set_key(aes, keymat, 256, TRUE);
1357
1358 /* Encode the buffer to be encrypted. Add padding to it too, at least
1359 block size of the cipher. */
1360
1361 /* Allocate buffer for encryption */
1362 len = silc_hmac_len(sha1hmac);
1363 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1364 enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1365 if (!enc) {
1366 silc_hmac_free(sha1hmac);
1367 silc_hash_free(sha1);
1368 silc_cipher_free(aes);
1369 return FALSE;
1370 }
1371
1372 /* Generate padding */
1373 for (i = 0; i < padlen; i++)
1374 tmp[i] = silc_rng_get_byte_fast(rng);
1375
1376 /* Put magic number */
1377 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1378 silc_buffer_pull(enc, 4);
1379
1380 /* Encode the buffer */
1381 silc_buffer_format(enc,
1382 SILC_STR_UI_INT(key_len),
1383 SILC_STR_UI_XNSTRING(key, key_len),
1384 SILC_STR_UI_XNSTRING(tmp, padlen),
1385 SILC_STR_END);
1386 silc_free(key);
1387
1388 /* Encrypt. */
1389 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1390 silc_cipher_get_iv(aes));
1391
1392 silc_buffer_push(enc, 4);
1393
1394 /* Compute HMAC over the encrypted data and append the MAC to data.
1395 The key is the first digest of the original key material. */
1396 key_len = silc_buffer_len(enc) - len;
1397 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1398 silc_hmac_update(sha1hmac, enc->data, key_len);
1399 silc_buffer_pull(enc, key_len);
1400 silc_hmac_final(sha1hmac, enc->data, NULL);
1401 silc_buffer_push(enc, key_len);
1402
1403 /* Cleanup */
1404 memset(keymat, 0, sizeof(keymat));
1405 memset(tmp, 0, sizeof(tmp));
1406 silc_hmac_free(sha1hmac);
1407 silc_hash_free(sha1);
1408 silc_cipher_free(aes);
1409
1410 switch (encoding) {
1411 case SILC_PKCS_FILE_BIN:
1412 break;
1413
1414 case SILC_PKCS_FILE_BASE64:
1415 data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1416 if (!data) {
1417 silc_buffer_clear(enc);
1418 silc_buffer_free(enc);
1419 return NULL;
1420 }
1421 silc_free(silc_buffer_steal(enc, NULL));
1422 silc_buffer_set(enc, data, strlen(data));
1423 break;
1424 }
1425
1426 key = enc->data;
1427 key_len = silc_buffer_len(enc);
1428
1429 /* Encode the data and save to file */
1430 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1431 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1432 buf = silc_buffer_alloc_size(len);
1433 if (!buf) {
1434 silc_buffer_free(enc);
1435 return NULL;
1436 }
1437 silc_buffer_format(buf,
1438 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1439 SILC_STR_UI_XNSTRING(key, key_len),
1440 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1441 SILC_STR_END);
1442
1443 silc_buffer_free(enc);
1444 data = silc_buffer_steal(buf, ret_len);
1445 silc_buffer_free(buf);
1446
1447 return data;
1448 }
1449
1450 /* Exports private key as SILC implementation style private key */
1451
silc_pkcs_silc_export_private_key(void * private_key,SilcUInt32 * ret_len)1452 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1453 SilcUInt32 *ret_len)
1454 {
1455 SilcSILCPrivateKey silc_privkey = private_key;
1456 const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1457 SilcBufferStruct alg_key;
1458 SilcBuffer buf = NULL;
1459 SilcAsn1 asn1 = NULL;
1460 unsigned char *prv = NULL, *key = NULL, *ret;
1461 SilcUInt32 prv_len, key_len, totlen;
1462
1463 SILC_LOG_DEBUG(("Encoding SILC private key"));
1464
1465 /* Export PKCS algorithm private key */
1466 if (pkcs->export_private_key)
1467 prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1468 if (!prv)
1469 return NULL;
1470 silc_buffer_set(&alg_key, prv, prv_len);
1471
1472 asn1 = silc_asn1_alloc();
1473 if (!asn1)
1474 goto err;
1475
1476 if (!strcmp(pkcs->name, "rsa")) {
1477 /* Parse the PKCS #1 private key */
1478 SilcMPInt n, e, d, dp, dq, qp, p, q;
1479 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1480 qp_len, p_len, q_len, len = 0;
1481 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1482
1483 if (!silc_asn1_decode(asn1, &alg_key,
1484 SILC_ASN1_SEQUENCE,
1485 SILC_ASN1_INT(NULL),
1486 SILC_ASN1_INT(&n),
1487 SILC_ASN1_INT(&e),
1488 SILC_ASN1_INT(&d),
1489 SILC_ASN1_INT(&p),
1490 SILC_ASN1_INT(&q),
1491 SILC_ASN1_INT(&dp),
1492 SILC_ASN1_INT(&dq),
1493 SILC_ASN1_INT(&qp),
1494 SILC_ASN1_END, SILC_ASN1_END))
1495 goto err;
1496
1497 /* Encode to SILC RSA private key */
1498 eb = silc_mp_mp2bin(&e, 0, &e_len);
1499 nb = silc_mp_mp2bin(&n, 0, &n_len);
1500 db = silc_mp_mp2bin(&d, 0, &d_len);
1501 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1502 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1503 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1504 pb = silc_mp_mp2bin(&p, 0, &p_len);
1505 qb = silc_mp_mp2bin(&q, 0, &q_len);
1506 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1507 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1508
1509 buf = silc_buffer_alloc_size(len);
1510 if (!buf)
1511 goto err;
1512 if (silc_buffer_format(buf,
1513 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1514 SILC_STR_UI_INT(e_len),
1515 SILC_STR_UI_XNSTRING(eb, e_len),
1516 SILC_STR_UI_INT(n_len),
1517 SILC_STR_UI_XNSTRING(nb, n_len),
1518 SILC_STR_UI_INT(d_len),
1519 SILC_STR_UI_XNSTRING(db, d_len),
1520 SILC_STR_UI_INT(dp_len),
1521 SILC_STR_UI_XNSTRING(dpb, dp_len),
1522 SILC_STR_UI_INT(dq_len),
1523 SILC_STR_UI_XNSTRING(dqb, dq_len),
1524 SILC_STR_UI_INT(qp_len),
1525 SILC_STR_UI_XNSTRING(qpb, qp_len),
1526 SILC_STR_UI_INT(p_len),
1527 SILC_STR_UI_XNSTRING(pb, p_len),
1528 SILC_STR_UI_INT(q_len),
1529 SILC_STR_UI_XNSTRING(qb, q_len),
1530 SILC_STR_END) < 0)
1531 goto err;
1532
1533 key = silc_buffer_steal(buf, &key_len);
1534 silc_buffer_free(buf);
1535 silc_free(nb);
1536 silc_free(eb);
1537 silc_free(db);
1538 silc_free(dpb);
1539 silc_free(dqb);
1540 silc_free(qpb);
1541 silc_free(pb);
1542 silc_free(qb);
1543
1544 } else if (!strcmp(pkcs->name, "dsa")) {
1545 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1546 goto err;
1547
1548 } else {
1549 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1550 goto err;
1551 }
1552
1553 /* Encode SILC private key */
1554 totlen = 2 + strlen(pkcs->name) + key_len;
1555 buf = silc_buffer_alloc_size(totlen);
1556 if (!buf)
1557 goto err;
1558 if (silc_buffer_format(buf,
1559 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1560 SILC_STR_UI32_STRING(pkcs->name),
1561 SILC_STR_UI_XNSTRING(key, key_len),
1562 SILC_STR_END) < 0)
1563 goto err;
1564
1565 ret = silc_buffer_steal(buf, ret_len);
1566 silc_buffer_free(buf);
1567 silc_free(prv);
1568 silc_free(key);
1569 silc_asn1_free(asn1);
1570
1571 return ret;
1572
1573 err:
1574 silc_free(prv);
1575 silc_free(key);
1576 if (buf)
1577 silc_buffer_free(buf);
1578 return NULL;
1579 }
1580
1581 /* Return key length */
1582
silc_pkcs_silc_private_key_bitlen(void * private_key)1583 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1584 {
1585 SilcSILCPrivateKey silc_privkey = private_key;
1586 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1587 }
1588
1589 /* Frees private key */
1590
silc_pkcs_silc_private_key_free(void * private_key)1591 void silc_pkcs_silc_private_key_free(void *private_key)
1592 {
1593 SilcSILCPrivateKey silc_privkey = private_key;
1594
1595 silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1596
1597 silc_free(silc_privkey);
1598 }
1599
1600
1601 /***************************** PKCS operations ******************************/
1602
1603 /* Encrypts as specified in SILC protocol specification */
1604
silc_pkcs_silc_encrypt(void * public_key,unsigned char * src,SilcUInt32 src_len,unsigned char * dst,SilcUInt32 dst_size,SilcUInt32 * ret_dst_len,SilcRng rng)1605 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1606 unsigned char *src,
1607 SilcUInt32 src_len,
1608 unsigned char *dst,
1609 SilcUInt32 dst_size,
1610 SilcUInt32 *ret_dst_len,
1611 SilcRng rng)
1612 {
1613 SilcSILCPublicKey silc_pubkey = public_key;
1614
1615 if (!silc_pubkey->pkcs->encrypt)
1616 return FALSE;
1617
1618 return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1619 src, src_len,
1620 dst, dst_size, ret_dst_len, rng);
1621 }
1622
1623 /* Decrypts as specified in SILC protocol specification */
1624
silc_pkcs_silc_decrypt(void * private_key,unsigned char * src,SilcUInt32 src_len,unsigned char * dst,SilcUInt32 dst_size,SilcUInt32 * ret_dst_len)1625 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1626 unsigned char *src,
1627 SilcUInt32 src_len,
1628 unsigned char *dst,
1629 SilcUInt32 dst_size,
1630 SilcUInt32 *ret_dst_len)
1631 {
1632 SilcSILCPrivateKey silc_privkey = private_key;
1633
1634 if (!silc_privkey->pkcs->decrypt)
1635 return FALSE;
1636
1637 return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1638 src, src_len,
1639 dst, dst_size, ret_dst_len);
1640 }
1641
1642 /* Signs as specified in SILC protocol specification */
1643
silc_pkcs_silc_sign(void * private_key,unsigned char * src,SilcUInt32 src_len,unsigned char * signature,SilcUInt32 signature_size,SilcUInt32 * ret_signature_len,SilcBool compute_hash,SilcHash hash)1644 SilcBool silc_pkcs_silc_sign(void *private_key,
1645 unsigned char *src,
1646 SilcUInt32 src_len,
1647 unsigned char *signature,
1648 SilcUInt32 signature_size,
1649 SilcUInt32 *ret_signature_len,
1650 SilcBool compute_hash,
1651 SilcHash hash)
1652 {
1653 SilcSILCPrivateKey silc_privkey = private_key;
1654
1655 if (!silc_privkey->pkcs->sign)
1656 return FALSE;
1657
1658 return silc_privkey->pkcs->sign(silc_privkey->private_key,
1659 src, src_len,
1660 signature, signature_size,
1661 ret_signature_len, compute_hash, hash);
1662 }
1663
1664 /* Verifies as specified in SILC protocol specification */
1665
silc_pkcs_silc_verify(void * public_key,unsigned char * signature,SilcUInt32 signature_len,unsigned char * data,SilcUInt32 data_len,SilcHash hash)1666 SilcBool silc_pkcs_silc_verify(void *public_key,
1667 unsigned char *signature,
1668 SilcUInt32 signature_len,
1669 unsigned char *data,
1670 SilcUInt32 data_len,
1671 SilcHash hash)
1672 {
1673 SilcSILCPublicKey silc_pubkey = public_key;
1674
1675 if (!silc_pubkey->pkcs->verify)
1676 return FALSE;
1677
1678 return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1679 signature, signature_len,
1680 data, data_len, hash);
1681 }
1682