5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "silcincludes.h"
27 /* List of all PKCS's in SILC. PKCS's don't support SIM's thus
28 only static declarations are possible. XXX: I hope this to change
30 SilcPKCSObject silc_pkcs_list[] =
32 /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
34 { "rsa", &silc_rsa_data_context,
35 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
36 silc_rsa_get_private_key, silc_rsa_set_public_key,
37 silc_rsa_set_private_key, silc_rsa_context_len,
38 silc_rsa_data_context_len, silc_rsa_set_arg,
39 silc_pkcs1_encrypt, silc_pkcs1_decrypt,
40 silc_pkcs1_sign, silc_pkcs1_verify },
43 /* Raw RSA operations */
44 { "rsa", &silc_rsa_data_context,
45 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
46 silc_rsa_get_private_key, silc_rsa_set_public_key,
47 silc_rsa_set_private_key, silc_rsa_context_len,
48 silc_rsa_data_context_len, silc_rsa_set_arg,
49 silc_rsa_encrypt, silc_rsa_decrypt,
50 silc_rsa_sign, silc_rsa_verify },
52 { NULL, NULL, NULL, NULL, NULL,
53 NULL, NULL, NULL, NULL, NULL, NULL }
56 /* Allocates a new SilcPKCS object. The new allocated object is returned
57 to the 'new_pkcs' argument. This function also initializes the data
58 context structure. Function returns 1 on success and 0 on error.
61 int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
65 SILC_LOG_DEBUG(("Allocating new PKCS object"));
67 for (i = 0; silc_pkcs_list[i].name; i++) {
68 if (!strcmp(silc_pkcs_list[i].name, name))
72 if (silc_pkcs_list[i].name == NULL)
75 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
77 /* Set the pointers */
78 (*new_pkcs)->pkcs = &silc_pkcs_list[i];
79 (*new_pkcs)->pkcs->data_context =
80 silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
81 (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
82 (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
87 /* Free's the PKCS object */
89 void silc_pkcs_free(SilcPKCS pkcs)
92 silc_free(pkcs->context);
95 /* Return TRUE if PKCS algorithm `name' is supported. */
97 int silc_pkcs_is_supported(const unsigned char *name)
101 for (i = 0; silc_pkcs_list[i].name; i++) {
102 if (!strcmp(silc_pkcs_list[i].name, name))
109 /* Returns comma separated list of supported PKCS algorithms */
111 char *silc_pkcs_get_supported()
117 for (i = 0; silc_pkcs_list[i].name; i++) {
118 len += strlen(silc_pkcs_list[i].name);
119 list = silc_realloc(list, len + 1);
121 memcpy(list + (len - strlen(silc_pkcs_list[i].name)),
122 silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
123 memcpy(list + len, ",", 1);
132 /* Returns the length of the key */
134 unsigned int silc_pkcs_get_key_len(SilcPKCS self)
136 return self->key_len;
139 /* Returns SILC style public key */
141 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len)
143 return pkcs->pkcs->get_public_key(pkcs->context, len);
146 /* Returns SILC style private key */
148 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
150 return pkcs->pkcs->get_private_key(pkcs->context, len);
153 /* Sets public key from SilcPublicKey. */
155 int silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
157 return pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
161 /* Sets public key from data. */
163 int silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
166 return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
169 /* Sets private key from SilcPrivateKey. */
171 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
173 return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
174 private_key->prv_len);
177 /* Sets private key from data. */
179 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
180 unsigned int prv_len)
182 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
185 /* Encodes and returns SILC public key identifier. If some of the
186 arguments is NULL those are not encoded into the identifier string.
187 Protocol says that at least username and host must be provided. */
189 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
190 char *email, char *org, char *country)
194 unsigned int len, tlen = 0;
196 if (!username || !host)
199 len = (username ? strlen(username) : 0) +
200 (host ? strlen(host) : 0) +
201 (realname ? strlen(realname) : 0) +
202 (email ? strlen(email) : 0) +
203 (org ? strlen(org) : 0) +
204 (country ? strlen(country) : 0);
209 len += 3 + 5 + 5 + 4 + 4 + 4;
210 buf = silc_buffer_alloc(len);
211 silc_buffer_pull_tail(buf, len);
214 silc_buffer_format(buf,
215 SILC_STR_UI32_STRING("UN="),
216 SILC_STR_UI32_STRING(username),
218 silc_buffer_pull(buf, 3 + strlen(username));
219 tlen = 3 + strlen(username);
223 silc_buffer_format(buf,
224 SILC_STR_UI32_STRING(", "),
225 SILC_STR_UI32_STRING("HN="),
226 SILC_STR_UI32_STRING(host),
228 silc_buffer_pull(buf, 5 + strlen(host));
229 tlen += 5 + strlen(host);
233 silc_buffer_format(buf,
234 SILC_STR_UI32_STRING(", "),
235 SILC_STR_UI32_STRING("RN="),
236 SILC_STR_UI32_STRING(realname),
238 silc_buffer_pull(buf, 5 + strlen(realname));
239 tlen += 5 + strlen(realname);
243 silc_buffer_format(buf,
244 SILC_STR_UI32_STRING(", "),
245 SILC_STR_UI32_STRING("E="),
246 SILC_STR_UI32_STRING(email),
248 silc_buffer_pull(buf, 4 + strlen(email));
249 tlen += 4 + strlen(email);
253 silc_buffer_format(buf,
254 SILC_STR_UI32_STRING(", "),
255 SILC_STR_UI32_STRING("O="),
256 SILC_STR_UI32_STRING(org),
258 silc_buffer_pull(buf, 4 + strlen(org));
259 tlen += 4 + strlen(org);
263 silc_buffer_format(buf,
264 SILC_STR_UI32_STRING(", "),
265 SILC_STR_UI32_STRING("C="),
266 SILC_STR_UI32_STRING(country),
268 silc_buffer_pull(buf, 4 + strlen(country));
269 tlen += 4 + strlen(country);
272 silc_buffer_push(buf, buf->data - buf->head);
273 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
274 memcpy(identifier, buf->data, tlen);
275 silc_buffer_free(buf);
280 /* Allocates SILC style public key formed from sent arguments. All data
283 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
287 SilcPublicKey public_key;
289 public_key = silc_calloc(1, sizeof(*public_key));
290 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
291 public_key->name = strdup(name);
292 public_key->identifier = strdup(identifier);
293 public_key->pk_len = pk_len;
294 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
295 memcpy(public_key->pk, pk, pk_len);
300 /* Free's public key */
302 void silc_pkcs_public_key_free(SilcPublicKey public_key)
305 silc_free(public_key->name);
306 silc_free(public_key->identifier);
307 silc_free(public_key->pk);
308 silc_free(public_key);
312 /* Allocates SILC private key formed from sent arguments. All data is
315 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
316 unsigned int prv_len)
318 SilcPrivateKey private_key;
320 private_key = silc_calloc(1, sizeof(*private_key));
321 private_key->name = strdup(name);
322 private_key->prv_len = prv_len;
323 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
324 memcpy(private_key->prv, prv, prv_len);
329 /* Free's private key */
331 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
334 silc_free(private_key->name);
335 silc_free(private_key->prv);
336 silc_free(private_key);
340 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
344 silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
349 buf = silc_buffer_alloc(public_key->len);
350 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
352 silc_buffer_format(buf,
353 SILC_STR_UI_INT(public_key->len),
354 SILC_STR_UI_SHORT(strlen(public_key->name)),
355 SILC_STR_UI32_STRING(public_key->name),
356 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
357 SILC_STR_UI32_STRING(public_key->identifier),
358 SILC_STR_UI_XNSTRING(public_key->pk,
362 *len = public_key->len;
364 ret = silc_calloc(buf->len, sizeof(*ret));
365 memcpy(ret, buf->data, buf->len);
366 silc_buffer_free(buf);
371 /* Encodes SILC style public key. Returns the encoded data. */
374 silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
375 char *pkcs, char *identifier,
382 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
383 buf = silc_buffer_alloc(totlen);
384 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
386 silc_buffer_format(buf,
387 SILC_STR_UI_INT(totlen),
388 SILC_STR_UI_SHORT(strlen(pkcs)),
389 SILC_STR_UI32_STRING(pkcs),
390 SILC_STR_UI_SHORT(strlen(identifier)),
391 SILC_STR_UI32_STRING(identifier),
392 SILC_STR_UI_XNSTRING(pk, pk_len),
397 ret = silc_calloc(buf->len, sizeof(*ret));
398 memcpy(ret, buf->data, buf->len);
399 silc_buffer_free(buf);
404 /* Decodes SILC style public key. Returns TRUE if the decoding was
405 successful. Allocates new public key as well. */
407 int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
408 SilcPublicKey *public_key)
412 unsigned short pkcs_len, identifier_len;
413 unsigned int totlen, key_len;
414 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
417 buf = silc_buffer_alloc(data_len);
418 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
419 silc_buffer_put(buf, data, data_len);
422 ret = silc_buffer_unformat(buf,
423 SILC_STR_UI_INT(&totlen),
426 silc_buffer_free(buf);
430 if (totlen != data_len) {
431 silc_buffer_free(buf);
435 /* Get algorithm name and identifier */
436 silc_buffer_pull(buf, 4);
438 silc_buffer_unformat(buf,
439 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
440 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
445 if (pkcs_len < 1 || identifier_len < 3 ||
446 pkcs_len + identifier_len > totlen)
449 /* See if we support this algorithm */
450 if (!silc_pkcs_is_supported(pkcs_name))
453 /* Protocol says that at least UN and HN must be provided as identifier,
455 if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
458 /* Get key data. We assume that rest of the buffer is key data. */
459 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
461 ret = silc_buffer_unformat(buf,
462 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
467 /* Try to set the key. If this fails the key must be malformed. This
468 code assumes that the PKCS routine checks the format of the key. */
469 silc_pkcs_alloc(pkcs_name, &alg);
470 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
475 *public_key = silc_calloc(1, sizeof(**public_key));
476 (*public_key)->len = totlen;
477 (*public_key)->name = pkcs_name;
478 (*public_key)->identifier = ident;
479 (*public_key)->pk = key_data;
480 (*public_key)->pk_len = key_len;
483 silc_buffer_free(buf);
488 silc_free(pkcs_name);
493 silc_buffer_free(buf);
497 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
500 silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
506 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
507 buf = silc_buffer_alloc(totlen);
508 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
510 silc_buffer_format(buf,
511 SILC_STR_UI_SHORT(strlen(private_key->name)),
512 SILC_STR_UI32_STRING(private_key->name),
513 SILC_STR_UI_XNSTRING(private_key->prv,
514 private_key->prv_len),
519 ret = silc_calloc(buf->len, sizeof(*ret));
520 memcpy(ret, buf->data, buf->len);
521 silc_buffer_free(buf);
526 /* Encodes SILC private key. Returns the encoded data. */
529 silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
530 char *pkcs, unsigned int *len)
536 totlen = 2 + strlen(pkcs) + prv_len;
537 buf = silc_buffer_alloc(totlen);
538 silc_buffer_pull_tail(buf, totlen);
540 silc_buffer_format(buf,
541 SILC_STR_UI_SHORT(strlen(pkcs)),
542 SILC_STR_UI32_STRING(pkcs),
543 SILC_STR_UI_XNSTRING(prv, prv_len),
548 ret = silc_calloc(buf->len, sizeof(*ret));
549 memcpy(ret, buf->data, buf->len);
550 silc_buffer_free(buf);
555 /* Decodes SILC style public key. Returns TRUE if the decoding was
556 successful. Allocates new private key as well. */
558 int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
559 SilcPrivateKey *private_key)
563 unsigned short pkcs_len;
564 unsigned int key_len;
565 unsigned char *pkcs_name = NULL, *key_data = NULL;
568 buf = silc_buffer_alloc(data_len);
569 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
570 silc_buffer_put(buf, data, data_len);
572 /* Get algorithm name and identifier */
574 silc_buffer_unformat(buf,
575 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
580 if (pkcs_len < 1 || pkcs_len > buf->truelen)
583 /* See if we support this algorithm */
584 if (!silc_pkcs_is_supported(pkcs_name))
587 /* Get key data. We assume that rest of the buffer is key data. */
588 silc_buffer_pull(buf, 2 + pkcs_len);
590 ret = silc_buffer_unformat(buf,
591 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
596 /* Try to set the key. If this fails the key must be malformed. This
597 code assumes that the PKCS routine checks the format of the key. */
598 silc_pkcs_alloc(pkcs_name, &alg);
599 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
604 *private_key = silc_calloc(1, sizeof(**private_key));
605 (*private_key)->name = pkcs_name;
606 (*private_key)->prv = key_data;
607 (*private_key)->prv_len = key_len;
610 silc_buffer_free(buf);
615 silc_free(pkcs_name);
618 silc_buffer_free(buf);
622 /* Internal routine to save public key */
624 static int silc_pkcs_save_public_key_internal(char *filename,
626 unsigned int data_len,
627 unsigned int encoding)
633 case SILC_PKCS_FILE_BIN:
635 case SILC_PKCS_FILE_PEM:
636 data = silc_encode_pem_file(data, data_len);
637 data_len = strlen(data);
641 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
642 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
643 buf = silc_buffer_alloc(len);
644 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
646 silc_buffer_format(buf,
647 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
648 SILC_STR_UI_XNSTRING(data, data_len),
649 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
653 if (silc_file_write(filename, buf->data, buf->len)) {
654 silc_buffer_free(buf);
658 silc_buffer_free(buf);
662 /* Saves public key into file */
664 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
665 unsigned int encoding)
668 unsigned int data_len;
670 data = silc_pkcs_public_key_encode(public_key, &data_len);
671 return silc_pkcs_save_public_key_internal(filename, data, data_len,
675 /* Saves public key into file */
677 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
678 unsigned int data_len,
679 unsigned int encoding)
681 return silc_pkcs_save_public_key_internal(filename, data, data_len,
685 /* Internal routine to save private key. */
687 static int silc_pkcs_save_private_key_internal(char *filename,
689 unsigned int data_len,
690 unsigned int encoding)
696 case SILC_PKCS_FILE_BIN:
698 case SILC_PKCS_FILE_PEM:
699 data = silc_encode_pem_file(data, data_len);
700 data_len = strlen(data);
704 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
705 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
706 buf = silc_buffer_alloc(len);
707 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
709 silc_buffer_format(buf,
710 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
711 SILC_STR_UI_XNSTRING(data, data_len),
712 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
715 /* Save into a file */
716 if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
717 silc_buffer_free(buf);
721 silc_buffer_free(buf);
725 /* Saves private key into file. */
726 /* XXX The buffer should be encrypted if passphrase is provided. */
728 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
729 unsigned char *passphrase,
730 unsigned int encoding)
733 unsigned int data_len;
735 data = silc_pkcs_private_key_encode(private_key, &data_len);
736 return silc_pkcs_save_private_key_internal(filename, data, data_len,
740 /* Saves private key into file. */
741 /* XXX The buffer should be encrypted if passphrase is provided. */
743 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
744 unsigned int data_len,
745 unsigned char *passphrase,
746 unsigned int encoding)
748 return silc_pkcs_save_private_key_internal(filename, data, data_len,
752 /* Loads public key from file and allocates new public key. Returns TRUE
753 is loading was successful. */
755 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
756 unsigned int encoding)
758 unsigned char *cp, *old, *data, byte;
759 unsigned int i, data_len, len;
761 old = data = silc_file_read(filename, &data_len);
765 /* Check start of file and remove header from the data. */
766 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
768 for (i = 0; i < len; i++) {
771 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
772 memset(old, 0, data_len);
778 /* Decode public key */
780 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
781 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
784 case SILC_PKCS_FILE_BIN:
786 case SILC_PKCS_FILE_PEM:
787 data = silc_decode_pem(data, len, &len);
791 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
792 memset(old, 0, data_len);
798 memset(old, 0, data_len);
803 /* Load private key from file and allocates new private key. Returns TRUE
804 if loading was successful. */
805 /* XXX Should support encrypted private key files */
807 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
808 unsigned int encoding)
810 unsigned char *cp, *old, *data, byte;
811 unsigned int i, data_len, len;
813 old = data = silc_file_read(filename, &data_len);
817 /* Check start of file and remove header from the data. */
818 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
820 for (i = 0; i < len; i++) {
823 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
824 memset(old, 0, data_len);
830 /* Decode private key */
832 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
833 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
836 case SILC_PKCS_FILE_BIN:
838 case SILC_PKCS_FILE_PEM:
839 data = silc_decode_pem(data, len, &len);
843 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
844 memset(old, 0, data_len);
850 memset(old, 0, data_len);