crypt: refactor TLS encryption API
[siplcs.git] / src / core / sipe-crypt-nss.c
blob1c0a13cf64d8736720794c51aeef0948682d7a28
1 /**
2 * @file sipe-crypt-nss.c
4 * pidgin-sipe
6 * Copyright (C) 2011-2015 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2010 pier11 <pier11@operamail.com>
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.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 /**
25 * Cypher routines implementation based on NSS.
26 * Includes: RC4, DES
29 #include "glib.h"
31 #include "nss.h"
33 * Work around a compiler error in NSS 3.13.x. Let's hope they fix it for
34 * 3.14.x. See also: https://bugzilla.mozilla.org/show_bug.cgi?id=702090
36 #if (NSS_VMAJOR == 3) && (NSS_VMINOR == 13)
37 #define __GNUC_MINOR __GNUC_MINOR__
38 #endif
39 #include "pk11pub.h"
41 #include "sipe-common.h"
42 #include "sipe-backend.h"
43 #include "sipe-crypt.h"
45 /* NSS specific initialization/shutdown */
46 void sipe_crypto_init(SIPE_UNUSED_PARAMETER gboolean production_mode)
48 if (!NSS_IsInitialized()) {
50 * I have a bad feeling about this: according to the NSS
51 * documentation, NSS can only be initialized once.
52 * Unfortunately there seems to be no way to initialize a
53 * "NSS context" that could then be used by the SIPE code
54 * to avoid colliding with other NSS users.
56 * This seems to work, so it'll have to do for now.
58 * It might also be required to move this to the backend
59 * so that the backend code can decide when it is OK to
60 * initialize NSS.
62 NSS_NoDB_Init(".");
63 SIPE_DEBUG_INFO_NOFORMAT("NSS initialised");
67 void sipe_crypto_shutdown(void)
69 /* do nothing for NSS.
70 * We don't want accedently switch off NSS possibly used by other plugin -
71 * ssl-nss in Pidgin for example.
75 /* PRIVATE methods */
77 static PK11Context*
78 sipe_crypt_ctx_create(CK_MECHANISM_TYPE cipherMech,
79 const guchar *key, gsize key_length,
80 const guchar *iv, gsize iv_length)
82 PK11SlotInfo* slot;
83 SECItem keyItem;
84 SECItem ivItem;
85 PK11SymKey* SymKey;
86 SECItem *SecParam;
87 PK11Context* EncContext;
89 /* For key */
90 slot = PK11_GetBestSlot(cipherMech, NULL);
92 keyItem.type = siBuffer;
93 keyItem.data = (unsigned char *)key;
94 keyItem.len = key_length;
96 SymKey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL);
98 /* Parameter for crypto context */
99 ivItem.type = siBuffer;
100 ivItem.data = (unsigned char *)iv;
101 ivItem.len = iv_length;
102 SecParam = PK11_ParamFromIV(cipherMech, &ivItem);
104 EncContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, SymKey, SecParam);
106 PK11_FreeSymKey(SymKey);
107 SECITEM_FreeItem(SecParam, PR_TRUE);
108 PK11_FreeSlot(slot);
110 return EncContext;
113 static void
114 sipe_crypt_ctx_encrypt(PK11Context* EncContext, const guchar *in, gsize length, guchar *out)
116 int tmp1_outlen;
118 PK11_CipherOp(EncContext, out, &tmp1_outlen, length, (unsigned char *)in, length);
121 static void
122 sipe_crypt_ctx_destroy(PK11Context* EncContext)
124 PK11_DestroyContext(EncContext, PR_TRUE);
127 static void
128 sipe_crypt(CK_MECHANISM_TYPE cipherMech,
129 const guchar *key, gsize key_length,
130 const guchar *plaintext, gsize plaintext_length,
131 guchar *encrypted_text)
133 void *EncContext;
135 EncContext = sipe_crypt_ctx_create(cipherMech, key, key_length, NULL, 0);
136 sipe_crypt_ctx_encrypt(EncContext, plaintext, plaintext_length, encrypted_text);
137 sipe_crypt_ctx_destroy(EncContext);
141 /* PUBLIC methods */
143 void
144 sipe_crypt_des(const guchar *key,
145 const guchar *plaintext, gsize plaintext_length,
146 guchar *encrypted_text)
148 sipe_crypt(CKM_DES_ECB, key, 8, plaintext, plaintext_length, encrypted_text);
151 void
152 sipe_crypt_rc4(const guchar *key, gsize key_length,
153 const guchar *plaintext, gsize plaintext_length,
154 guchar *encrypted_text)
156 sipe_crypt(CKM_RC4, key, key_length, plaintext, plaintext_length, encrypted_text);
159 gboolean
160 sipe_crypt_rsa_encrypt(gpointer public, gsize modulus_length,
161 const guchar *plaintext,
162 guchar *encrypted_text)
164 SECStatus result = PK11_PubEncryptRaw(public,
165 encrypted_text, (guchar *) plaintext,
166 modulus_length, NULL);
167 return(result == SECSuccess);
170 gboolean
171 sipe_crypt_rsa_decrypt(gpointer private, gsize modulus_length,
172 const guchar *encrypted_text,
173 guchar *plaintext)
175 unsigned int length;
176 SECStatus result = PK11_PubDecryptRaw(private,
177 (guchar *) encrypted_text, &length, modulus_length,
178 plaintext, modulus_length);
179 return((result == SECSuccess) && (length == modulus_length));
182 guchar *sipe_crypt_rsa_sign(gpointer private,
183 const guchar *digest, gsize digest_length,
184 gsize *signature_length)
186 SECItem digItem;
187 SECItem sigItem;
188 SECStatus length;
190 length = PK11_SignatureLen(private);
191 if (length < 0) return(NULL);
193 /* digest to sign (= encrypt) with private key */
194 digItem.data = (guchar *) digest;
195 digItem.len = digest_length;
197 /* signature */
198 sigItem.data = g_malloc(length);
199 sigItem.len = length;
201 length = PK11_Sign(private, &sigItem, &digItem);
202 if (length != SECSuccess) {
203 g_free(sigItem.data);
204 return(NULL);
207 *signature_length = sigItem.len;
208 return(sigItem.data);
211 gboolean sipe_crypt_verify_rsa(gpointer public,
212 const guchar *digest, gsize digest_length,
213 const guchar *signature, gsize signature_length)
215 SECItem digItem;
216 SECItem sigItem;
218 /* digest to verify against */
219 digItem.data = (guchar *) digest;
220 digItem.len = digest_length;
222 /* signature to decrypt with public key -> digest to compare */
223 sigItem.data = (guchar *) signature;
224 sigItem.len = signature_length;
226 return(PK11_Verify(public, &sigItem, &digItem, NULL) == SECSuccess);
230 /* Stream RC4 cipher for file transfer */
231 gpointer
232 sipe_crypt_ft_start(const guchar *key)
234 return sipe_crypt_ctx_create(CKM_RC4, key, 16, NULL, 0);
237 void
238 sipe_crypt_ft_stream(gpointer context,
239 const guchar *in, gsize length,
240 guchar *out)
242 sipe_crypt_ctx_encrypt(context, in, length, out);
245 void
246 sipe_crypt_ft_destroy(gpointer context)
248 sipe_crypt_ctx_destroy(context);
252 * Stream RC4 cipher for TLS
254 * basically the same as for FT, but with variable key length
256 gpointer sipe_crypt_tls_start(const guchar *key, gsize key_length)
258 return sipe_crypt_ctx_create(CKM_RC4, key, key_length, NULL, 0);
261 void sipe_crypt_tls_stream(gpointer context,
262 const guchar *in, gsize length,
263 guchar *out)
265 sipe_crypt_ctx_encrypt(context, in, length, out);
268 void sipe_crypt_tls_destroy(gpointer context)
270 sipe_crypt_ctx_destroy(context);
273 /* Block AES-CBC cipher for TLS */
274 void sipe_crypt_tls_block(const guchar *key, gsize key_length,
275 const guchar *iv, gsize iv_length,
276 const guchar *in, gsize length,
277 guchar *out)
279 PK11Context* context = sipe_crypt_ctx_create(CKM_AES_CBC,
280 key, key_length,
281 iv, iv_length);
282 if (context) {
283 sipe_crypt_ctx_encrypt(context, in, length, out);
284 sipe_crypt_ctx_destroy(context);
289 Local Variables:
290 mode: c
291 c-file-style: "bsd"
292 indent-tabs-mode: t
293 tab-width: 8
294 End: