5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 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.
21 #include "silcincludes.h"
25 /* List of all PKCS's in SILC. PKCS's don't support SIM's thus
26 only static declarations are possible. XXX: I hope this to change
28 SilcPKCSObject silc_pkcs_list[] =
30 { "rsa", &silc_rsa_data_context,
31 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
32 silc_rsa_get_private_key, silc_rsa_set_public_key,
33 silc_rsa_set_private_key, silc_rsa_context_len,
34 silc_rsa_data_context_len, silc_rsa_set_arg,
35 silc_rsa_encrypt, silc_rsa_decrypt,
36 silc_rsa_sign, silc_rsa_verify },
38 { NULL, NULL, NULL, NULL, NULL,
39 NULL, NULL, NULL, NULL, NULL, NULL }
42 /* Allocates a new SilcPKCS object. The new allocated object is returned
43 to the 'new_pkcs' argument. This function also initializes the data
44 context structure. Function returns 1 on success and 0 on error.
47 int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
51 SILC_LOG_DEBUG(("Allocating new PKCS object"));
53 for (i = 0; silc_pkcs_list[i].name; i++) {
54 if (!strcmp(silc_pkcs_list[i].name, name))
58 if (silc_pkcs_list[i].name == NULL)
61 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
63 /* Set the pointers */
64 (*new_pkcs)->pkcs = &silc_pkcs_list[i];
65 (*new_pkcs)->pkcs->data_context =
66 silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
67 (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
68 (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
73 /* Free's the PKCS object */
75 void silc_pkcs_free(SilcPKCS pkcs)
78 silc_free(pkcs->context);
81 /* Return TRUE if PKCS algorithm `name' is supported. */
83 int silc_pkcs_is_supported(const unsigned char *name)
87 for (i = 0; silc_pkcs_list[i].name; i++) {
88 if (!strcmp(silc_pkcs_list[i].name, name))
95 /* Returns comma separated list of supported PKCS algorithms */
97 char *silc_pkcs_get_supported()
103 for (i = 0; silc_pkcs_list[i].name; i++) {
104 len += strlen(silc_pkcs_list[i].name);
105 list = silc_realloc(list, len + 1);
107 memcpy(list + (len - strlen(silc_pkcs_list[i].name)),
108 silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
109 memcpy(list + len, ",", 1);
118 /* Returns the length of the key */
120 unsigned int silc_pkcs_get_key_len(SilcPKCS self)
122 return self->key_len;
125 /* Returns SILC style public key */
127 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len)
129 return pkcs->pkcs->get_public_key(pkcs->context, len);
132 /* Returns SILC style private key */
134 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
136 return pkcs->pkcs->get_private_key(pkcs->context, len);
139 /* Sets public key from SilcPublicKey. */
141 int silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
143 return pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
147 /* Sets public key from data. */
149 int silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
152 return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
155 /* Sets private key from SilcPrivateKey. */
157 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
159 return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
160 private_key->prv_len);
163 /* Sets private key from data. */
165 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
166 unsigned int prv_len)
168 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
171 /* Encodes and returns SILC public key identifier. If some of the
172 arguments is NULL those are not encoded into the identifier string.
173 Protocol says that at least username and host must be provided. */
175 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
176 char *email, char *org, char *country)
180 unsigned int len, tlen = 0;
182 if (!username || !host)
185 len = (username ? strlen(username) : 0) +
186 (host ? strlen(host) : 0) +
187 (realname ? strlen(realname) : 0) +
188 (email ? strlen(email) : 0) +
189 (org ? strlen(org) : 0) +
190 (country ? strlen(country) : 0);
195 len += 3 + 5 + 5 + 4 + 4 + 4;
196 buf = silc_buffer_alloc(len);
197 silc_buffer_pull_tail(buf, len);
200 silc_buffer_format(buf,
201 SILC_STR_UI32_STRING("UN="),
202 SILC_STR_UI32_STRING(username),
204 silc_buffer_pull(buf, 3 + strlen(username));
205 tlen = 3 + strlen(username);
209 silc_buffer_format(buf,
210 SILC_STR_UI32_STRING(", "),
211 SILC_STR_UI32_STRING("HN="),
212 SILC_STR_UI32_STRING(host),
214 silc_buffer_pull(buf, 5 + strlen(host));
215 tlen += 5 + strlen(host);
219 silc_buffer_format(buf,
220 SILC_STR_UI32_STRING(", "),
221 SILC_STR_UI32_STRING("RN="),
222 SILC_STR_UI32_STRING(realname),
224 silc_buffer_pull(buf, 5 + strlen(realname));
225 tlen += 5 + strlen(realname);
229 silc_buffer_format(buf,
230 SILC_STR_UI32_STRING(", "),
231 SILC_STR_UI32_STRING("E="),
232 SILC_STR_UI32_STRING(email),
234 silc_buffer_pull(buf, 4 + strlen(email));
235 tlen += 4 + strlen(email);
239 silc_buffer_format(buf,
240 SILC_STR_UI32_STRING(", "),
241 SILC_STR_UI32_STRING("O="),
242 SILC_STR_UI32_STRING(org),
244 silc_buffer_pull(buf, 4 + strlen(org));
245 tlen += 4 + strlen(org);
249 silc_buffer_format(buf,
250 SILC_STR_UI32_STRING(", "),
251 SILC_STR_UI32_STRING("C="),
252 SILC_STR_UI32_STRING(country),
254 silc_buffer_pull(buf, 4 + strlen(country));
255 tlen += 4 + strlen(country);
258 silc_buffer_push(buf, buf->data - buf->head);
259 identifier = silc_calloc(tlen, sizeof(*identifier));
260 memcpy(identifier, buf->data, tlen);
261 silc_buffer_free(buf);
266 /* Allocates SILC style public key formed from sent arguments. All data
269 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
273 SilcPublicKey public_key;
275 public_key = silc_calloc(1, sizeof(*public_key));
276 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
277 public_key->name = strdup(name);
278 public_key->identifier = strdup(identifier);
279 public_key->pk_len = pk_len;
280 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
281 memcpy(public_key->pk, pk, pk_len);
286 /* Free's public key */
288 void silc_pkcs_public_key_free(SilcPublicKey public_key)
291 silc_free(public_key->name);
292 silc_free(public_key->identifier);
293 silc_free(public_key->pk);
294 silc_free(public_key);
298 /* Allocates SILC private key formed from sent arguments. All data is
301 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
302 unsigned int prv_len)
304 SilcPrivateKey private_key;
306 private_key = silc_calloc(1, sizeof(*private_key));
307 private_key->name = strdup(name);
308 private_key->prv_len = prv_len;
309 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
310 memcpy(private_key->prv, prv, prv_len);
315 /* Free's private key */
317 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
320 silc_free(private_key->name);
321 silc_free(private_key->prv);
322 silc_free(private_key);
326 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
330 silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
335 buf = silc_buffer_alloc(public_key->len);
336 silc_buffer_pull_tail(buf, public_key->len);
338 silc_buffer_format(buf,
339 SILC_STR_UI_INT(public_key->len),
340 SILC_STR_UI_SHORT(strlen(public_key->name)),
341 SILC_STR_UI32_STRING(public_key->name),
342 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
343 SILC_STR_UI32_STRING(public_key->identifier),
344 SILC_STR_UI_XNSTRING(public_key->pk,
348 *len = public_key->len;
350 ret = silc_calloc(buf->len, sizeof(*ret));
351 memcpy(ret, buf->data, buf->len);
352 silc_buffer_free(buf);
357 /* Encodes SILC style public key. Returns the encoded data. */
360 silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
361 char *pkcs, char *identifier,
368 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
369 buf = silc_buffer_alloc(totlen);
370 silc_buffer_pull_tail(buf, totlen);
372 silc_buffer_format(buf,
373 SILC_STR_UI_INT(totlen),
374 SILC_STR_UI_SHORT(strlen(pkcs)),
375 SILC_STR_UI32_STRING(pkcs),
376 SILC_STR_UI_SHORT(strlen(identifier)),
377 SILC_STR_UI32_STRING(identifier),
378 SILC_STR_UI_XNSTRING(pk, pk_len),
383 ret = silc_calloc(buf->len, sizeof(*ret));
384 memcpy(ret, buf->data, buf->len);
385 silc_buffer_free(buf);
390 /* Decodes SILC style public key. Returns TRUE if the decoding was
391 successful. Allocates new public key as well. */
393 int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
394 SilcPublicKey *public_key)
398 unsigned short pkcs_len, identifier_len;
399 unsigned int totlen, key_len;
400 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
402 buf = silc_buffer_alloc(data_len);
403 silc_buffer_pull_tail(buf, data_len);
404 silc_buffer_put(buf, data, data_len);
407 silc_buffer_unformat(buf,
408 SILC_STR_UI_INT(&totlen),
411 if (totlen != data_len) {
412 silc_buffer_free(buf);
416 /* Get algorithm name and identifier */
417 silc_buffer_pull(buf, 4);
418 silc_buffer_unformat(buf,
419 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
420 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
423 if (pkcs_len < 1 || identifier_len < 3 ||
424 pkcs_len + identifier_len > totlen)
427 /* See if we support this algorithm */
428 if (!silc_pkcs_is_supported(pkcs_name))
431 /* Protocol says that at least UN and HN must be provided as identifier,
433 if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
436 /* Get key data. We assume that rest of the buffer is key data. */
437 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
439 silc_buffer_unformat(buf,
440 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
443 /* Try to set the key. If this fails the key must be malformed. This
444 code assumes that the PKCS routine checks the format of the key. */
445 silc_pkcs_alloc(pkcs_name, &alg);
446 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
451 *public_key = silc_calloc(1, sizeof(**public_key));
452 (*public_key)->len = totlen;
453 (*public_key)->name = pkcs_name;
454 (*public_key)->identifier = ident;
455 (*public_key)->pk = key_data;
456 (*public_key)->pk_len = key_len;
459 silc_buffer_free(buf);
464 silc_free(pkcs_name);
469 silc_buffer_free(buf);
473 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
476 silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
482 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
483 buf = silc_buffer_alloc(totlen);
484 silc_buffer_pull_tail(buf, totlen);
486 silc_buffer_format(buf,
487 SILC_STR_UI_SHORT(strlen(private_key->name)),
488 SILC_STR_UI32_STRING(private_key->name),
489 SILC_STR_UI_XNSTRING(private_key->prv,
490 private_key->prv_len),
495 ret = silc_calloc(buf->len, sizeof(*ret));
496 memcpy(ret, buf->data, buf->len);
497 silc_buffer_free(buf);
502 /* Encodes SILC private key. Returns the encoded data. */
505 silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
506 char *pkcs, unsigned int *len)
512 totlen = 2 + strlen(pkcs) + prv_len;
513 buf = silc_buffer_alloc(totlen);
514 silc_buffer_pull_tail(buf, totlen);
516 silc_buffer_format(buf,
517 SILC_STR_UI_SHORT(strlen(pkcs)),
518 SILC_STR_UI32_STRING(pkcs),
519 SILC_STR_UI_XNSTRING(prv, prv_len),
524 ret = silc_calloc(buf->len, sizeof(*ret));
525 memcpy(ret, buf->data, buf->len);
526 silc_buffer_free(buf);
531 /* Decodes SILC style public key. Returns TRUE if the decoding was
532 successful. Allocates new private key as well. */
534 int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
535 SilcPrivateKey *private_key)
539 unsigned short pkcs_len;
540 unsigned int key_len;
541 unsigned char *pkcs_name = NULL, *key_data = NULL;
543 buf = silc_buffer_alloc(data_len);
544 silc_buffer_pull_tail(buf, data_len);
545 silc_buffer_put(buf, data, data_len);
547 /* Get algorithm name and identifier */
548 silc_buffer_unformat(buf,
549 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
552 if (pkcs_len < 1 || pkcs_len > buf->truelen)
555 /* See if we support this algorithm */
556 if (!silc_pkcs_is_supported(pkcs_name))
559 /* Get key data. We assume that rest of the buffer is key data. */
560 silc_buffer_pull(buf, 2 + pkcs_len);
562 silc_buffer_unformat(buf,
563 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
566 /* Try to set the key. If this fails the key must be malformed. This
567 code assumes that the PKCS routine checks the format of the key. */
568 silc_pkcs_alloc(pkcs_name, &alg);
569 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
574 *private_key = silc_calloc(1, sizeof(**private_key));
575 (*private_key)->name = pkcs_name;
576 (*private_key)->prv = key_data;
577 (*private_key)->prv_len = key_len;
580 silc_buffer_free(buf);
585 silc_free(pkcs_name);
588 silc_buffer_free(buf);
592 /* Internal routine to save public key */
594 static int silc_pkcs_save_public_key_internal(char *filename,
596 unsigned int data_len)
601 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
602 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
603 buf = silc_buffer_alloc(len);
604 silc_buffer_pull_tail(buf, len);
606 silc_buffer_format(buf,
607 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
608 SILC_STR_UI_XNSTRING(data, data_len),
609 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
612 /* Save into a file */
613 if (silc_file_write(filename, buf->data, buf->len)) {
614 silc_buffer_free(buf);
618 silc_buffer_free(buf);
622 /* Saves public key into file */
623 /* XXX encoding should be defined (PEM or binary). */
625 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key)
628 unsigned int data_len;
630 data = silc_pkcs_public_key_encode(public_key, &data_len);
631 return silc_pkcs_save_public_key_internal(filename, data, data_len);
634 /* Saves public key into file */
635 /* XXX encoding should be defined (PEM or binary). */
637 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
638 unsigned int data_len)
640 return silc_pkcs_save_public_key_internal(filename, data, data_len);
643 /* Internal routine to save private key. */
645 static int silc_pkcs_save_private_key_internal(char *filename,
647 unsigned int data_len)
652 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
653 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
654 buf = silc_buffer_alloc(len);
655 silc_buffer_pull_tail(buf, len);
657 silc_buffer_format(buf,
658 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
659 SILC_STR_UI_XNSTRING(data, data_len),
660 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
663 /* Save into a file */
664 if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
665 silc_buffer_free(buf);
669 silc_buffer_free(buf);
673 /* Saves private key into file. */
674 /* XXX The buffer should be encrypted if passphrase is provided. */
675 /* XXX encoding should be defined (PEM or binary). */
677 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
678 unsigned char *passphrase)
681 unsigned int data_len;
683 data = silc_pkcs_private_key_encode(private_key, &data_len);
684 return silc_pkcs_save_private_key_internal(filename, data, data_len);
687 /* Saves private key into file. */
688 /* XXX The buffer should be encrypted if passphrase is provided. */
689 /* XXX encoding should be defined (PEM or binary). */
691 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
692 unsigned int data_len,
693 unsigned char *passphrase)
695 return silc_pkcs_save_private_key_internal(filename, data, data_len);
698 /* Loads public key from file and allocates new public key. Returns TRUE
699 is loading was successful. */
700 /* XXX Encoding should be defined. */
702 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key)
704 unsigned char *cp, *old, *data, byte;
705 unsigned int i, data_len, len;
707 old = data = silc_file_read(filename, &data_len);
711 /* Check start of file and remove header from the data. */
712 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
714 for (i = 0; i < len; i++) {
717 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
718 memset(old, 0, data_len);
724 /* Decode public key */
726 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
727 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
728 if (!silc_pkcs_public_key_decode(data, len, public_key)) {
729 memset(old, 0, data_len);
735 memset(old, 0, data_len);
740 /* Load private key from file and allocates new private key. Returns TRUE
741 if loading was successful. */
742 /* XXX Encoding should be defined. */
743 /* XXX Should support encrypted private key files */
745 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key)
747 unsigned char *cp, *old, *data, byte;
748 unsigned int i, data_len, len;
750 old = data = silc_file_read(filename, &data_len);
754 /* Check start of file and remove header from the data. */
755 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
757 for (i = 0; i < len; i++) {
760 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
761 memset(old, 0, data_len);
767 /* Decode private key */
769 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
770 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
771 if (!silc_pkcs_private_key_decode(data, len, private_key)) {
772 memset(old, 0, data_len);
778 memset(old, 0, data_len);