1 /*             NSS keys for the Pidgin-Encryption plugin                  */
2 /*             Copyright (C) 2001 William Tompkins                        */
3 
4 /* This plugin is free software, distributed under the GNU General Public */
5 /* License.                                                               */
6 /* Please see the file "COPYING" distributed with this source code        */
7 /* for more details                                                       */
8 /*                                                                        */
9 /*                                                                        */
10 /*    This software is distributed in the hope that it will be useful,    */
11 /*   but WITHOUT ANY WARRANTY; without even the implied warranty of       */
12 /*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    */
13 /*   General Public License for more details.                             */
14 
15 /*   To compile and use:                                                  */
16 /*     See INSTALL file.                                                  */
17 
18 #include "internal.h"
19 
20 #include <gdk/gdk.h>
21 #include <gtk/gtk.h>
22 #include <gtk/gtkplug.h>
23 
24 #include <debug.h>
25 #include <gtkdialogs.h>
26 
27 #include "glib.h"
28 
29 #include <string.h>
30 #include <assert.h>
31 
32 #ifdef _WIN32
33 #include "win32dep.h"
34 #endif
35 
36 #include "rsa_nss.h"
37 
38 #include <nspr.h>
39 #include <nss.h>
40 #include <ssl.h>
41 #include <secmod.h>
42 #include <pk11func.h>
43 #include <keyhi.h>
44 #include <nssb64.h>
45 
46 
47 #include "nls.h"
48 #include "nss_mgf1.h"
49 #include "nss_oaep.h"
50 #include "nss_pss.h"
51 #include "cryptutil.h"
52 #include "keys.h"
53 #include "cryptproto.h"
54 #include "state_ui.h"
55 
56 char* rsa_nss_proto_string="NSS 1.0";
57 
58 crypt_proto* rsa_nss_proto;
59 
60 /*Functions exported through crypt_proto structure */
61 static int              rsa_nss_encrypt(unsigned char**, unsigned char*, int, crypt_key*);
62 static int              rsa_nss_decrypt(unsigned char**, unsigned char*, int, crypt_key*);
63 static int              rsa_nss_sign(unsigned char**, unsigned char*, int, crypt_key*, crypt_key*);
64 static int              rsa_nss_auth(unsigned char**, unsigned char*, int, crypt_key*, const char* name);
65 static crypt_key*       rsa_nss_make_key_from_str(char *key_str);
66 static GString*         rsa_nss_key_to_gstr(crypt_key* inkey);
67 static char*            rsa_nss_parseable(char* key);
68 static crypt_key*       rsa_nss_parse_sent_key(char *key_str);
69 static GString*         rsa_nss_make_sendable_key(crypt_key* inkey, const char* name);
70 static gchar*           rsa_nss_make_key_id(crypt_key* inkey);
71 
72 void                    rsa_nss_gen_key_pair(crypt_key **, crypt_key **,
73                                              const char* name, int keysize);
74 static void             rsa_nss_free(crypt_key*);
75 static crypt_key*       rsa_nss_make_pub_from_priv(crypt_key* priv);
76 static int              rsa_nss_calc_unencrypted_size(struct crypt_key*, int);
77 static int              rsa_nss_calc_unsigned_size(struct crypt_key*, int);
78 
79 /* internals */
80 void rsa_nss_test(crypt_key *pub, crypt_key *priv);
81 
82 
83 gboolean rsa_nss_init() {
84 
85    gboolean nss_loaded_ok = FALSE;
86 
87   	PurplePlugin *plugin = purple_plugins_find_with_name("NSS");
88 
89    if (plugin != NULL) {
90       nss_loaded_ok = purple_plugin_is_loaded(plugin);
91       if (!nss_loaded_ok) {
92          nss_loaded_ok = purple_plugin_load(plugin);
93       }
94    }
95 
96    if (!nss_loaded_ok) {
97       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "Initializing NSS without Purple support\n");
98       /* Purple doesn't seem to have NSS support: try to load it ourselves: */
99       PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
100       NSS_NoDB_Init(NULL);
101 
102       /* TODO: Fix this so autoconf does the work trying to find this lib. */
103       SECMOD_AddNewModule("Builtins",
104 #ifndef _WIN32
105                           LIBDIR "/libnssckbi.so",
106 #else
107                           "nssckbi.dll",
108 #endif
109                           0, 0);
110       NSS_SetDomesticPolicy();
111 
112       /*       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", _("Can't load the NSS plugin\n")); */
113       /*       PE_error_window(_("Purple was not compiled with the NSS plugin enabled.  " */
114       /*                       "Pidgin-Encryption requires the NSS plugin to function.")); */
115       /*       return FALSE; */
116    }
117 
118    rsa_nss_proto = g_malloc(sizeof(crypt_proto));
119    crypt_proto_list = g_slist_prepend(crypt_proto_list, rsa_nss_proto);
120 
121    rsa_nss_proto->encrypt = rsa_nss_encrypt;
122    rsa_nss_proto->decrypt = rsa_nss_decrypt;
123    rsa_nss_proto->sign = rsa_nss_sign;
124    rsa_nss_proto->auth = rsa_nss_auth;
125 
126    rsa_nss_proto->make_key_from_str = rsa_nss_make_key_from_str;
127    rsa_nss_proto->key_to_gstr = rsa_nss_key_to_gstr;
128    rsa_nss_proto->parseable = rsa_nss_parseable;
129    rsa_nss_proto->parse_sent_key = rsa_nss_parse_sent_key;
130    rsa_nss_proto->make_sendable_key = rsa_nss_make_sendable_key;
131    rsa_nss_proto->make_key_id = rsa_nss_make_key_id;
132    rsa_nss_proto->gen_key_pair = rsa_nss_gen_key_pair;
133    rsa_nss_proto->free = rsa_nss_free;
134    rsa_nss_proto->make_pub_from_priv = rsa_nss_make_pub_from_priv;
135    rsa_nss_proto->calc_unencrypted_size = rsa_nss_calc_unencrypted_size;
136    rsa_nss_proto->calc_unsigned_size = rsa_nss_calc_unsigned_size;
137    rsa_nss_proto->name = rsa_nss_proto_string;
138 
139    return TRUE;
140 }
141 
142 static void rsa_nss_free(crypt_key* key){
143    if (key->store.rsa_nss.pub) {
144       SECKEY_DestroyPublicKey(key->store.rsa_nss.pub);
145       key->store.rsa_nss.pub = 0;
146    }
147    if (key->store.rsa_nss.priv) {
148       SECKEY_DestroyPrivateKey(key->store.rsa_nss.priv);
149       key->store.rsa_nss.priv = 0;
150    }
151 }
152 
153 static SECItem*
154 get_random_iv(CK_MECHANISM_TYPE mechType)
155 {
156    int        iv_size = PK11_GetIVLength(mechType);
157    SECItem   *iv;
158    SECStatus  rv;
159 
160    iv = PORT_ZNew(SECItem);
161    g_assert(iv != 0);
162    g_assert(iv_size != 0);
163 
164    iv->data = PORT_NewArray(unsigned char, iv_size);
165    g_assert(iv->data != 0);
166    iv->len = iv_size;
167    rv = PK11_GenerateRandom(iv->data, iv->len);
168    g_assert(rv == SECSuccess);
169 
170    return iv;
171 }
172 
173 static void generate_digest(char* digest, SECKEYPublicKey* key) {
174    SECItem *hash = PK11_MakeIDFromPubKey(&key->u.rsa.modulus);
175    int i = 0, digestPos = 0;
176 
177    while (i < hash->len && digestPos < KEY_DIGEST_LENGTH) {
178       sprintf(digest + digestPos, "%02x", hash->data[i]);
179       ++i;
180       digestPos += 2;
181    }
182    SECITEM_ZfreeItem (hash, PR_TRUE);
183 }
184 
185 static void generate_fingerprint(char* print, SECKEYPublicKey* key) {
186    SECItem *hash = PK11_MakeIDFromPubKey(&key->u.rsa.modulus);
187    int i;
188 
189    for (i= 0; i < hash->len - 1; ++i) {
190       sprintf(print + (3*i), "%02x:", hash->data[i]);
191    }
192    sprintf(print + 3 * (hash->len - 1), "%02x", hash->data[(hash->len - 1)]);
193    SECITEM_ZfreeItem (hash, PR_TRUE);
194 }
195 
196 static SECKEYPublicKey *
197 copy_public_rsa_key(SECKEYPublicKey *pubk) {
198    SECKEYPublicKey *copyk;
199    PRArenaPool *arena;
200    SECStatus rv;
201 
202    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
203    g_assert(arena != NULL);
204 
205    copyk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey));
206    g_assert(copyk != NULL);
207 
208    copyk->arena = arena;
209    copyk->keyType = pubk->keyType;
210 
211    copyk->pkcs11Slot = NULL;   /* go get own reference */
212    copyk->pkcs11ID = CK_INVALID_HANDLE;
213 
214    rv = SECITEM_CopyItem(arena, &copyk->u.rsa.modulus,
215                          &pubk->u.rsa.modulus);
216    g_assert(rv == SECSuccess);
217 
218    rv = SECITEM_CopyItem (arena, &copyk->u.rsa.publicExponent,
219                           &pubk->u.rsa.publicExponent);
220    g_assert(rv == SECSuccess);
221 
222    return copyk;
223 }
224 
225 void rsa_nss_gen_key_pair(crypt_key **pub_key, crypt_key **priv_key,
226                           const char* name, int keysize) {
227 
228    GtkWidget *status_window, *main_box, *label1, *label2;
229    char labelText[1000];
230    PK11RSAGenParams rsaParams;
231    PK11SlotInfo *slot;
232 
233    CK_MECHANISM_TYPE multiType[2] = {CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_DES_CBC_PAD};
234 
235    /* Create the widgets */
236 
237    PIDGIN_DIALOG(status_window);
238    gtk_window_set_wmclass(GTK_WINDOW(status_window), "keygen", "Pidgin");
239    gtk_widget_realize(status_window);
240    gtk_container_set_border_width(GTK_CONTAINER(status_window), 10);
241    gtk_widget_set_size_request(status_window, 350, 100);
242    gtk_window_set_title(GTK_WINDOW(status_window), "Status");
243    main_box = gtk_vbox_new(FALSE, 0);
244    gtk_container_add(GTK_CONTAINER(status_window), main_box);
245    gtk_widget_show(main_box);
246 
247    g_snprintf(labelText, sizeof(labelText), _("Generating RSA Key Pair for %s"),
248               name);
249    label1 = gtk_label_new (labelText);
250    label2 = gtk_label_new (_("This may take a little bit..."));
251 
252    gtk_container_add (GTK_CONTAINER (main_box), label1);
253    gtk_widget_show(label1);
254    gtk_container_add (GTK_CONTAINER (main_box), label2);
255    gtk_widget_show(label2);
256 
257    gtk_widget_show (status_window);
258 
259    // I don't understand: if I remove one of these
260    // two loops, the contents of the status window don't
261    // get drawn.  Hmm...
262    while (gtk_events_pending()) {
263       gtk_main_iteration_do(FALSE);
264    }
265    gtk_main_iteration();
266    while (gtk_events_pending()) {
267       gtk_main_iteration_do(FALSE);
268    }
269 
270    *priv_key = g_malloc(sizeof(crypt_key));
271 
272    rsaParams.keySizeInBits = keysize;
273    rsaParams.pe = 65537L;
274 
275    slot = PK11_GetBestSlotMultiple(multiType, 2, 0);
276 
277    /* Generate "session" (first FALSE), "not sensitive" (next FALSE) key */
278    (*priv_key)->store.rsa_nss.priv =
279       PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams,
280                            &(*priv_key)->store.rsa_nss.pub,
281                            PR_FALSE, PR_FALSE, 0);
282 
283    if (!(*priv_key)->store.rsa_nss.priv) {
284       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption",
285                  _("Could not generate key.  NSS Error: %d\n"),
286                  PORT_GetError());
287       exit(0);
288    }
289 
290    (*priv_key)->proto = rsa_nss_proto;
291    g_snprintf((*priv_key)->length, sizeof((*priv_key)->length), "%d", keysize);
292 
293    generate_digest((*priv_key)->digest, (*priv_key)->store.rsa_nss.pub);
294    generate_fingerprint((*priv_key)->fingerprint, (*priv_key)->store.rsa_nss.pub);
295 
296    (*pub_key) = rsa_nss_make_pub_from_priv(*priv_key);
297 
298    gtk_widget_hide(status_window);
299    gtk_widget_destroy(status_window);
300 }
301 
302 char* rsa_nss_parseable(char *key) {
303    /* If the key is ours, return a pointer to the ':' after our token */
304    /* otherwise return 0                                              */
305    /* if we were more sophisticated, we could look for older versions */
306    /* of our protocol here, and accept them too.                      */
307    if (strncmp(rsa_nss_proto_string, key, strlen(rsa_nss_proto_string)) == 0) {
308       return key + strlen(rsa_nss_proto_string);
309    } else {
310       return 0;
311    }
312 }
313 
314 
315 static GString* append_priv_key_to_gstr(GString *str, SECKEYPrivateKey* priv) {
316 
317    /* for now, we hope that everyone can use DES3.  This is for wrapping   */
318    /* private keys, which isn't actually secure at this point anyways      */
319    /* (security provided by the OS: no one else can read/write the keyfile */
320    const CK_MECHANISM_TYPE SymEncryptionType = CKM_DES3_CBC_PAD;
321 
322    PK11SlotInfo *symSlot;
323    PK11SymKey *symKey;
324 
325    SECItem symKeyItem;  /* storage space for binary key import */
326    unsigned char symKeyData[24] = {0};
327 
328    SECItem *iv = NULL;  /* IV for CBC encoding                 */
329 
330    SECItem exportedKey; /* storage space for exported key */
331    unsigned char exportedKeyData[5000] = {0};
332 
333    char* tmpstr;
334    int errCode;
335 
336    if (priv == 0) return str;
337 
338    /* Wrap key using a null symmetric key.  When/If we add password protection to
339       keys, we can generate the symmetric key from a hashed password instead */
340    symSlot = PK11_GetBestSlot(SymEncryptionType, NULL);
341    g_assert(symSlot != 0);
342 
343    symKeyItem.data = &symKeyData[0];
344    symKeyItem.len = sizeof(symKeyData);
345 
346    symKey  = PK11_ImportSymKey(symSlot, PK11_GetKeyGen(SymEncryptionType),
347                                PK11_OriginUnwrap, CKA_WRAP, &symKeyItem, NULL);
348 
349    iv = get_random_iv(SymEncryptionType);
350 
351    exportedKey.len = sizeof(exportedKeyData);
352    exportedKey.data = exportedKeyData;
353 
354    errCode = PK11_WrapPrivKey(symSlot, symKey, priv, SymEncryptionType, iv,
355                               &exportedKey, NULL);
356 
357    g_assert(errCode == SECSuccess);
358 
359 
360    g_string_append(str, ",");
361 
362    tmpstr = NSSBase64_EncodeItem(0, 0, 0, iv);
363    g_string_append(str, tmpstr);
364    PORT_Free(tmpstr);
365 
366    g_string_append(str, ",");
367 
368    tmpstr = NSSBase64_EncodeItem(0, 0, 0, &exportedKey);
369    g_string_append(str, tmpstr);
370    PORT_Free(tmpstr);
371 
372    g_string_append(str, ",");
373 
374    PK11_FreeSymKey(symKey);
375    SECITEM_ZfreeItem(iv, PR_TRUE);
376 
377    /* The Base64 routine may have inserted lots of return chars into the string: */
378    /*   take them out.                                                           */
379    PE_strip_returns(str);
380 
381    return str;
382 }
383 
384 static GString* append_pub_key_to_gstr(GString *str, SECKEYPublicKey* pub) {
385    char *tmpstr;
386    SECItem *exportedKey;
387 
388    if (pub == 0) return str;
389 
390    exportedKey = SECKEY_EncodeDERSubjectPublicKeyInfo(pub);
391    //   exportedKey = PK11_DEREncodePublicKey(pub);
392 
393    tmpstr = NSSBase64_EncodeItem(0, 0, 0, exportedKey);
394    g_string_append(str, tmpstr);
395 
396    PORT_Free(tmpstr);
397    SECITEM_FreeItem (exportedKey, PR_TRUE);
398 
399    /* The Base64 routine may have inserted lots of return chars into the string: take them out. */
400    PE_strip_returns(str);
401 
402    return str;
403 }
404 
405 
406 GString* rsa_nss_make_sendable_key(crypt_key* inkey, const char* name) {
407    GString *outString = g_string_new("");
408 
409    gchar* nonce_str = PE_new_incoming_nonce(name);
410    g_string_append(outString, nonce_str);
411 
412    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Sending Nonce with key: %s\n", nonce_str);
413 
414    g_free(nonce_str);
415 
416    g_string_append(outString, ",");
417 
418    append_pub_key_to_gstr(outString, inkey->store.rsa_nss.pub);
419 
420    return outString;
421 }
422 
423 gchar* rsa_nss_make_key_id(crypt_key* inkey) {
424    return PE_nonce_to_str(&inkey->store.rsa_nss.nonce);
425 }
426 
427 crypt_key* rsa_nss_parse_sent_key(char *key_str) {
428    gchar** split_key = g_strsplit(key_str, ",", 2);
429    crypt_key* key;
430 
431    if ((split_key[0] == 0) || (split_key[1] == 0)) {
432       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "Error parsing RSANSS nonce/key\n");
433       g_strfreev(split_key);
434       return 0;
435    }
436 
437    key = rsa_nss_make_key_from_str(split_key[1]);
438 
439    if (key == 0) {
440       g_strfreev(split_key);
441       return 0;
442    }
443 
444    PE_str_to_nonce(&key->store.rsa_nss.nonce, split_key[0]);
445    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Received Nonce with key: %s\n", split_key[0]);
446 
447    g_strfreev(split_key);
448 
449    return key;
450 }
451 
452 GString* rsa_nss_key_to_gstr(crypt_key* inkey) {
453    GString *outString = g_string_new("");
454 
455    append_pub_key_to_gstr(outString, inkey->store.rsa_nss.pub);
456 
457    append_priv_key_to_gstr(outString, inkey->store.rsa_nss.priv);
458 
459    return outString;
460 }
461 
462 crypt_key* rsa_nss_make_key_from_str(char *key_str){
463    gchar **split_key;
464 
465    crypt_key* key = g_malloc(sizeof(crypt_key));
466 
467    /* For Private keys: */
468    const CK_MECHANISM_TYPE SymEncryptionType = CKM_DES3_CBC_PAD;
469    PK11SlotInfo *symSlot;
470    PK11SymKey *symKey;
471    SECItem *pubKeyValue;
472    SECItem symKeyItem;  /* storage space for binary key import */
473    unsigned char symKeyData[24] = {0};
474    SECItem *iv = 0, *wrappedKey = 0, label;
475    CK_ATTRIBUTE_TYPE attribs[3] = { CKA_SIGN, CKA_DECRYPT, CKA_SIGN_RECOVER };
476    const int NumAttribs = 3;
477    int cur_piece;
478 
479    CERTSubjectPublicKeyInfo *certPubKeyInfo;
480 
481    /* key_str looks like "KKKKK" or "KKKKK,NNNN,MMMM", where */
482    /* KKKKK is the Base64 encoding of the public key, or              */
483    /* NNNN is the Base64 encoding of the IV, and                      */
484    /* MMMM is the Base64 encoding of the encrypted private key        */
485 
486 
487    key->proto = rsa_nss_proto;
488 
489    split_key = g_strsplit(key_str, ",", 3);
490 
491    key->store.rsa_nss.pub = 0;
492    key->store.rsa_nss.priv = 0;
493 
494    cur_piece = 0;
495 
496    // Check for public key part, and get it:
497 
498    if (split_key[cur_piece] == 0) {
499       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "(%d) %s",
500                  1, _("Error parsing RSANSS key\n"));
501       g_free(key);
502       g_strfreev(split_key);
503       return 0;
504    }
505 
506    wrappedKey = NSSBase64_DecodeBuffer(0, 0, split_key[cur_piece], strlen(split_key[cur_piece]));
507 
508    if (wrappedKey == 0) {
509       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "(%d) %s",
510                  2, _("Error parsing RSANSS key\n"));
511       g_free(key);
512       g_strfreev(split_key);
513       return 0;
514    }
515 
516    certPubKeyInfo = SECKEY_DecodeDERSubjectPublicKeyInfo(wrappedKey);
517 
518    SECITEM_FreeItem(wrappedKey, PR_TRUE);
519 
520    if (certPubKeyInfo == NULL) {
521       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "(%d) %s",
522                  3, _("Error parsing RSANSS key\n"));
523       g_free(key);
524       g_strfreev(split_key);
525       return 0;
526    }
527 
528    key->store.rsa_nss.pub = SECKEY_ExtractPublicKey(certPubKeyInfo);
529 
530    if (key->store.rsa_nss.pub == NULL) {
531       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "(%d) %s",
532                  4, _("Error parsing RSANSS key\n"));
533       g_free(key);
534       g_strfreev(split_key);
535       return 0;
536    }
537 
538    SECKEY_DestroySubjectPublicKeyInfo(certPubKeyInfo);
539 
540    generate_digest(key->digest, key->store.rsa_nss.pub);
541    generate_fingerprint(key->fingerprint, key->store.rsa_nss.pub);
542 
543    g_snprintf(key->length, sizeof(key->length), "%d",
544               8 * SECKEY_PublicKeyStrength(key->store.rsa_nss.pub));
545 
546    if (split_key[++cur_piece] == 0) {
547       /* No private part, so return a public key: */
548       g_strfreev(split_key);
549       return key;
550    }
551 
552    /* ------------------------------------------------------------------------ */
553    /*  Extract Private key:                                                    */
554    /*                                                                          */
555 
556    iv = NSSBase64_DecodeBuffer(0, 0, split_key[cur_piece],
557                                strlen(split_key[cur_piece]));
558 
559    if (split_key[++cur_piece] == 0) {
560       /* only part of a private key */
561       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "(%d) %s",
562                  5, _("Error parsing RSANSS key\n"));
563       g_free(key);
564       g_strfreev(split_key);
565       /* SECItem_FreeItem will ignore null arguments, so just call it to clean up */
566       SECITEM_ZfreeItem (iv, PR_TRUE);
567       return 0;
568    }
569 
570    wrappedKey =  NSSBase64_DecodeBuffer(0, 0, split_key[cur_piece],
571                                         strlen(split_key[cur_piece]));
572 
573    if ((iv == 0) || (wrappedKey == 0)) {
574       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "(%d) %s",
575                  6, _("Error parsing RSANSS key\n"));
576       g_free(key);
577       g_strfreev(split_key);
578       SECITEM_ZfreeItem (iv, PR_TRUE);
579       SECITEM_ZfreeItem (wrappedKey, PR_TRUE);
580       return 0;
581    }
582 
583    pubKeyValue = SECITEM_DupItem(&key->store.rsa_nss.pub->u.rsa.modulus);
584 
585    symSlot = PK11_GetBestSlot(SymEncryptionType, NULL);
586    g_assert(symSlot != 0);
587 
588    symKeyItem.data = &symKeyData[0];
589    symKeyItem.len = sizeof(symKeyData);
590 
591    symKey  = PK11_ImportSymKey(symSlot, PK11_GetKeyGen(SymEncryptionType),
592                                PK11_OriginUnwrap, CKA_WRAP, &symKeyItem, NULL);
593 
594    if (!symKey) {
595       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "(%d) %s",
596                  7, _("Error parsing RSANSS key\n"));
597       g_strfreev(split_key);
598 
599       SECKEY_DestroyPublicKey(key->store.rsa_nss.pub);
600       SECITEM_ZfreeItem (iv, PR_TRUE);
601       SECITEM_ZfreeItem (pubKeyValue, PR_TRUE);
602       g_free(key);
603       return 0;
604    }
605 
606    label.data = NULL; label.len = 0;
607 
608    key->store.rsa_nss.priv =
609       PK11_UnwrapPrivKey(symSlot, symKey, SymEncryptionType, iv,
610                          wrappedKey, &label, pubKeyValue,
611                          PR_FALSE, PR_FALSE, CKK_RSA, attribs, NumAttribs, 0);
612 
613    SECITEM_ZfreeItem (iv, PR_TRUE);
614    SECITEM_ZfreeItem (wrappedKey, PR_TRUE);
615    SECITEM_FreeItem (pubKeyValue, PR_TRUE);
616    PK11_FreeSymKey(symKey);
617 
618    if (key->store.rsa_nss.priv == 0) {
619       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "(%d) %s",
620                  8, _("Error parsing RSANSS key\n"));
621       g_strfreev(split_key);
622 
623       SECKEY_DestroyPublicKey(key->store.rsa_nss.pub);
624       g_free(key);
625       return 0;
626    }
627    /* should sanity check public/private pair */
628 
629    g_strfreev(split_key);
630 
631    return key;
632 }
633 
634 
635 crypt_key* rsa_nss_make_pub_from_priv(crypt_key* priv_key) {
636    crypt_key* pub_key = g_malloc(sizeof(crypt_key));
637 
638    pub_key->proto = rsa_nss_proto;
639    strcpy(pub_key->length, priv_key->length);
640    strncpy(pub_key->digest, priv_key->digest, KEY_DIGEST_LENGTH);
641    strncpy(pub_key->fingerprint, priv_key->fingerprint, KEY_FINGERPRINT_LENGTH);
642 
643    pub_key->store.rsa_nss.pub = copy_public_rsa_key(priv_key->store.rsa_nss.pub);
644    pub_key->store.rsa_nss.priv = 0;
645 
646    return pub_key;
647 }
648 
649 int rsa_nss_encrypt(unsigned char** encrypted, unsigned char* msg, int msg_len,
650                     crypt_key* pub_key){
651 
652    SECKEYPublicKey * key = pub_key->store.rsa_nss.pub;
653 
654    int modulus_len = SECKEY_PublicKeyStrength(key);
655 
656    int unpadded_block_len = oaep_max_unpadded_len(modulus_len);
657 
658    int num_blocks = ((msg_len - 1) / unpadded_block_len) + 1;
659 
660    unsigned char* msg_cur, *encrypt_cur;
661 
662    int msg_block_len;
663 
664    unsigned char *padded_block = g_malloc(modulus_len);
665 
666    int ret;
667    SECStatus rv;
668 
669    //   purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Starting Encrypt\n");
670 
671    *encrypted = g_malloc(num_blocks * modulus_len);
672 
673    msg_cur = msg;
674    encrypt_cur = *encrypted;
675 
676    while (msg_cur < msg + msg_len) {
677 
678       msg_block_len = unpadded_block_len;
679       if (msg_cur + msg_block_len > msg + msg_len) {
680          msg_block_len = msg + msg_len - msg_cur;
681       }
682 
683       ret = oaep_pad_block(padded_block, modulus_len, msg_cur, msg_block_len);
684       if (!ret) {
685          g_free(padded_block);
686          g_free(*encrypted);
687          *encrypted = 0;
688          return 0;
689       }
690       rv = PK11_PubEncryptRaw(key, encrypt_cur, padded_block,
691                               modulus_len, 0);
692       if (rv != SECSuccess) {
693          g_free(padded_block);
694          g_free(*encrypted);
695          *encrypted = 0;
696          return 0;
697       }
698 
699       msg_cur += msg_block_len;
700       encrypt_cur += modulus_len;
701    }
702 
703    g_free(padded_block);
704    //   purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Ending Encrypt\n");
705 
706    return (encrypt_cur - *encrypted);
707 }
708 
709 int rsa_nss_decrypt(unsigned char** decrypted, unsigned char* msg, int msg_len,
710                     crypt_key* priv_key){
711 
712    SECKEYPrivateKey * key = priv_key->store.rsa_nss.priv;
713 
714    int modulus_len = SECKEY_PublicKeyStrength(priv_key->store.rsa_nss.pub);
715 
716    int unpadded_block_len = oaep_max_unpadded_len(modulus_len);
717 
718    int num_blocks = msg_len / modulus_len;
719 
720    unsigned char* msg_cur, *decrypt_cur;
721 
722    unsigned int decrypt_block_size;
723 
724    unsigned char *padded_block = g_malloc(modulus_len);
725 
726    int ret;
727    SECStatus rv;
728 
729    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Starting Decrypt\n");
730 
731    *decrypted = g_malloc(num_blocks * unpadded_block_len + 1);
732 
733    msg_cur = msg;
734    decrypt_cur = *decrypted;
735 
736    if (num_blocks * modulus_len != msg_len) {  /* not an even number of blocks */
737       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "Not a multiple of block len: %d %d %d\n",
738                  num_blocks, modulus_len, msg_len);
739       g_free(padded_block);
740       g_free(*decrypted);
741       *decrypted = 0;
742       return 0;
743    }
744 
745    while (msg_cur < msg + msg_len) {
746 
747       rv = PK11_PubDecryptRaw(key, padded_block, &decrypt_block_size, modulus_len,
748                               msg_cur, modulus_len);
749 
750       if (rv != SECSuccess) {
751          purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "PubDecryptRaw failed %d\n", rv);
752          g_free(padded_block);
753          g_free(*decrypted);
754          *decrypted = 0;
755          return 0;
756       }
757 
758       g_assert(decrypt_block_size == modulus_len); /* for now. Don't understand how */
759                                                    /* this could not be true        */
760 
761       ret = oaep_unpad_block(decrypt_cur, &decrypt_block_size, padded_block, modulus_len);
762       if (!ret) {
763          purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "OAEP unpadding failed\n");
764          g_free(padded_block);
765          g_free(*decrypted);
766          *decrypted = 0;
767          return 0;
768       }
769 
770       msg_cur += modulus_len;
771       decrypt_cur += decrypt_block_size;
772    }
773 
774    g_free(padded_block);
775 
776    /* Null terminate what just came out, in case someone tries to use it as a string */
777    *decrypt_cur = 0;
778 
779    //   purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Ending Decrypt\n");
780    return (decrypt_cur - *decrypted);
781 }
782 
783 int rsa_nss_sign(unsigned char** signed_msg, unsigned char* msg, int msg_len,
784                  crypt_key* priv_key, crypt_key* pub_key) {
785 
786    SECKEYPrivateKey * key = priv_key->store.rsa_nss.priv;
787    int modulus_len = SECKEY_PublicKeyStrength(priv_key->store.rsa_nss.pub);
788    unsigned char *sig_pos, *tmp_sig;
789 
790    SECStatus rv;
791    unsigned int out_block_size;
792 
793    const int salt_len = 20;
794 
795    gchar *nonce_str = PE_nonce_to_str(&pub_key->store.rsa_nss.nonce);
796    int nonce_len = strlen(nonce_str);
797 
798    PE_incr_nonce(&pub_key->store.rsa_nss.nonce);
799 
800    *signed_msg = g_malloc(msg_len + modulus_len + nonce_len + 1);
801    tmp_sig = g_malloc(modulus_len);
802    memcpy(*signed_msg, nonce_str, nonce_len);
803    (*signed_msg)[nonce_len]=':';
804 
805    memcpy(*signed_msg + nonce_len + 1, msg, msg_len);
806    sig_pos = *signed_msg + msg_len + nonce_len + 1 ;
807 
808    g_free(nonce_str);
809 
810    pss_generate_sig(tmp_sig, modulus_len, *signed_msg, msg_len + nonce_len + 1, salt_len);
811 
812    rv = PK11_PubDecryptRaw(key, sig_pos, &out_block_size, modulus_len,
813                            tmp_sig, modulus_len);
814 
815    if (rv != SECSuccess) {
816       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "PK11_PubDecryptRaw Failed\n");
817       g_free(*signed_msg);
818       g_free(tmp_sig);
819       *signed_msg = 0;
820       return 0;
821    }
822 
823    g_assert(out_block_size == modulus_len);  /* dunno why they yield out_block_size */
824 
825    g_free(tmp_sig);
826 
827    return msg_len + nonce_len + 1 + modulus_len;
828 }
829 
830 // Returns length of authed string, or 0 if not authenticated
831 // g_malloc's space for the authed string, and null terminates the result
832 // If returning zero, may return a message ID (nonce) as the authed string
833 
834 int rsa_nss_auth(unsigned char** authed, unsigned char* msg, int msg_len,
835                  crypt_key* pub_key, const char* name) {
836 
837    SECKEYPublicKey * key = pub_key->store.rsa_nss.pub;
838    int modulus_len = SECKEY_PublicKeyStrength(key);
839    unsigned char *tmp_sig;
840 
841    SECStatus rv;
842    int verified;
843 
844    gchar *nonce_msg, **nonce_msg_split;
845 
846    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Starting Auth\n");
847 
848    *authed = 0;
849 
850    if (msg_len < modulus_len) {
851       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "Bad msg_len in Auth\n");
852       return 0;
853    }
854 
855    tmp_sig = g_malloc(modulus_len);
856 
857    rv = PK11_PubEncryptRaw(key, tmp_sig, msg + msg_len - modulus_len,
858                            modulus_len, 0);
859 
860    if (rv != SECSuccess) {
861       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "PK11_PubEncryptRaw Failed\n");
862       g_free(tmp_sig);
863       return 0;
864    }
865 
866    /*   purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Auth 2\n"); */
867 
868    verified = pss_check_sig(tmp_sig, modulus_len, msg, msg_len - modulus_len);
869 
870    g_free(tmp_sig);
871 
872    if (!verified) {
873       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", _("Bad signature on message (len %d, mod %d)\n"),
874                  msg_len, modulus_len);
875       return 0;
876    }
877 
878    /*    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Auth 3\n"); */
879 
880    nonce_msg = g_strndup((char*)msg, msg_len - modulus_len);
881    nonce_msg_split = g_strsplit(nonce_msg, ":", 2);
882    g_free(nonce_msg);
883 
884    /*    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Auth 4\n"); */
885 
886    if ((nonce_msg_split[0] == 0) || (nonce_msg_split[1] == 0)) {
887       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "No Nonce in message\n");
888       g_strfreev(nonce_msg_split);
889       return 0;
890    }
891 
892    /*    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Auth 5\n"); */
893 
894    if (!PE_check_incoming_nonce(name, nonce_msg_split[0])) {
895       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "Bad Nonce in message\n");
896       /* a hack: return the nonce that was sent, to send to other side, to cause */
897       /*         message to be re-sent */
898       *authed = (unsigned char*) g_strdup(nonce_msg_split[0]);
899 
900       g_strfreev(nonce_msg_split);
901       return 0;
902    }
903 
904    /*    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Auth 6\n"); */
905 
906    *authed = (unsigned char*)nonce_msg_split[1];
907    g_free(nonce_msg_split[0]);
908    g_free(nonce_msg_split);
909 
910    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Auth End\n");
911 
912    return strlen((char*)*authed);
913 }
914 
915 int rsa_nss_calc_unencrypted_size(struct crypt_key* key, int insize) {
916    int modulus_len = SECKEY_PublicKeyStrength(key->store.rsa_nss.pub);
917    int unpadded_block_len = oaep_max_unpadded_len(modulus_len);
918 
919    int num_blocks = insize / modulus_len; /* floor: max number of blocks that could fit */
920 
921    return num_blocks * unpadded_block_len;
922 }
923 
924 int rsa_nss_calc_unsigned_size(struct crypt_key* key, int insize) {
925    int modulus_len, nonce_len;
926 
927    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "calc_unsigned_size\n");
928 
929    modulus_len = SECKEY_PublicKeyStrength(key->store.rsa_nss.pub);
930    nonce_len = PE_nonce_str_len();
931 
932    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "modulus_len:%d:%d\n", modulus_len, nonce_len);
933 
934    if (insize < modulus_len + nonce_len) return 0;
935    return insize - modulus_len - nonce_len - 1;  /* -1 from ":" after nonce */
936 }
937 
938 
939