device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm-util / crypto_nss.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3 /*
4  * Dan Williams <dcbw@redhat.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301 USA.
20  *
21  * Copyright 2007 - 2009 Red Hat, Inc.
22  */
23
24 #include "nm-default.h"
25
26 #include <prinit.h>
27 #include <nss.h>
28 #include <pk11pub.h>
29 #include <pkcs11t.h>
30 #include <cert.h>
31 #include <prerror.h>
32 #include <p12.h>
33 #include <ciferfam.h>
34 #include <p12plcy.h>
35
36 #include "crypto.h"
37
38 static gboolean initialized = FALSE;
39
40 gboolean
41 crypto_init (GError **error)
42 {
43         SECStatus ret;
44
45         if (initialized)
46                 return TRUE;
47
48         PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 1);
49         ret = NSS_NoDB_Init (NULL);
50         if (ret != SECSuccess) {
51                 g_set_error (error, NM_CRYPTO_ERROR,
52                              NM_CRYPTO_ERR_INIT_FAILED,
53                              _("Failed to initialize the crypto engine: %d."),
54                              PR_GetError ());
55                 PR_Cleanup ();
56                 return FALSE;
57         }
58
59         SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
60         SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
61         SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
62         SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
63         SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
64         SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
65         SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
66
67         initialized = TRUE;
68         return TRUE;
69 }
70
71 gboolean
72 crypto_md5_hash (const char *salt,
73                  const gsize salt_len,
74                  const char *password,
75                  gsize password_len,
76                  char *buffer,
77                  gsize buflen,
78                  GError **error)
79 {
80         PK11Context *ctx;
81         int nkey = buflen;
82         unsigned int digest_len;
83         int count = 0;
84         char digest[MD5_HASH_LEN];
85         char *p = buffer;
86
87         if (salt)
88                 g_return_val_if_fail (salt_len >= 8, FALSE);
89
90         g_return_val_if_fail (password != NULL, FALSE);
91         g_return_val_if_fail (password_len > 0, FALSE);
92         g_return_val_if_fail (buffer != NULL, FALSE);
93         g_return_val_if_fail (buflen > 0, FALSE);
94
95         ctx = PK11_CreateDigestContext (SEC_OID_MD5);
96         if (!ctx) {
97                 g_set_error (error, NM_CRYPTO_ERROR,
98                              NM_CRYPTO_ERR_MD5_INIT_FAILED,
99                              _("Failed to initialize the MD5 context: %d."),
100                              PORT_GetError ());
101                 return FALSE;
102         }
103
104         while (nkey > 0) {
105                 int i = 0;
106
107                 PK11_DigestBegin (ctx);
108                 if (count++)
109                         PK11_DigestOp (ctx, (const unsigned char *) digest, digest_len);
110                 PK11_DigestOp (ctx, (const unsigned char *) password, password_len);
111                 if (salt)
112                         PK11_DigestOp (ctx, (const unsigned char *) salt, 8); /* Only use 8 bytes of salt */
113                 PK11_DigestFinal (ctx, (unsigned char *) digest, &digest_len, sizeof (digest));
114
115                 while (nkey && (i < digest_len)) {
116                         *(p++) = digest[i++];
117                         nkey--;
118                 }
119         }
120
121         memset (digest, 0, sizeof (digest));
122         PK11_DestroyContext (ctx, PR_TRUE);
123         return TRUE;
124 }
125
126 char *
127 crypto_decrypt (const char *cipher,
128                 int key_type,
129                 GByteArray *data,
130                 const char *iv,
131                 const gsize iv_len,
132                 const char *key,
133                 const gsize key_len,
134                 gsize *out_len,
135                 GError **error)
136 {
137         char *output = NULL;
138         int decrypted_len = 0;
139         CK_MECHANISM_TYPE cipher_mech;
140         PK11SlotInfo *slot = NULL;
141         SECItem key_item;
142         PK11SymKey *sym_key = NULL;
143         SECItem *sec_param = NULL;
144         PK11Context *ctx = NULL;
145         SECStatus s;
146         gboolean success = FALSE;
147         unsigned int pad_len = 0, extra = 0;
148         guint32 i, real_iv_len = 0;
149
150         if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
151                 cipher_mech = CKM_DES3_CBC_PAD;
152                 real_iv_len = 8;
153         } else if (!strcmp (cipher, CIPHER_DES_CBC)) {
154                 cipher_mech = CKM_DES_CBC_PAD;
155                 real_iv_len = 8;
156         } else if (!strcmp (cipher, CIPHER_AES_CBC)) {
157                 cipher_mech = CKM_AES_CBC_PAD;
158                 real_iv_len = 16;
159         } else {
160                 g_set_error (error, NM_CRYPTO_ERROR,
161                              NM_CRYPTO_ERR_UNKNOWN_CIPHER,
162                              _("Private key cipher '%s' was unknown."),
163                              cipher);
164                 return NULL;
165         }
166
167         if (iv_len < real_iv_len) {
168                 g_set_error (error, NM_CRYPTO_ERROR,
169                              NM_CRYPTO_ERR_RAW_IV_INVALID,
170                              _("Invalid IV length (must be at least %d)."),
171                              real_iv_len);
172                 return NULL;
173         }
174
175         output = g_malloc0 (data->len);
176
177         slot = PK11_GetBestSlot (cipher_mech, NULL);
178         if (!slot) {
179                 g_set_error (error, NM_CRYPTO_ERROR,
180                              NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
181                              _("Failed to initialize the decryption cipher slot."));
182                 goto out;
183         }
184
185         key_item.data = (unsigned char *) key;
186         key_item.len = key_len;
187         sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_DECRYPT, &key_item, NULL);
188         if (!sym_key) {
189                 g_set_error (error, NM_CRYPTO_ERROR,
190                              NM_CRYPTO_ERR_CIPHER_SET_KEY_FAILED,
191                              _("Failed to set symmetric key for decryption."));
192                 goto out;
193         }
194
195         key_item.data = (unsigned char *) iv;
196         key_item.len = real_iv_len;
197         sec_param = PK11_ParamFromIV (cipher_mech, &key_item);
198         if (!sec_param) {
199                 g_set_error (error, NM_CRYPTO_ERROR,
200                              NM_CRYPTO_ERR_CIPHER_SET_IV_FAILED,
201                              _("Failed to set IV for decryption."));
202                 goto out;
203         }
204
205         ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_DECRYPT, sym_key, sec_param);
206         if (!ctx) {
207                 g_set_error (error, NM_CRYPTO_ERROR,
208                              NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
209                              _("Failed to initialize the decryption context."));
210                 goto out;
211         }
212
213         s = PK11_CipherOp (ctx,
214                            (unsigned char *) output,
215                            &decrypted_len,
216                            data->len,
217                            data->data,
218                            data->len);
219         if (s != SECSuccess) {
220                 g_set_error (error, NM_CRYPTO_ERROR,
221                              NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
222                              _("Failed to decrypt the private key: %d."),
223                              PORT_GetError ());
224                 goto out;
225         }
226
227         if (decrypted_len > data->len) {
228                 g_set_error (error, NM_CRYPTO_ERROR,
229                              NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
230                              _("Failed to decrypt the private key: decrypted data too large."));
231                 goto out;
232         }
233
234         s = PK11_DigestFinal (ctx,
235                               (unsigned char *) (output + decrypted_len),
236                               &extra,
237                               data->len - decrypted_len);
238         if (s != SECSuccess) {
239                 g_set_error (error, NM_CRYPTO_ERROR,
240                              NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
241                              _("Failed to finalize decryption of the private key: %d."),
242                              PORT_GetError ());
243                 goto out;
244         }
245         decrypted_len += extra;
246         pad_len = data->len - decrypted_len;
247
248         /* Check if the padding at the end of the decrypted data is valid */
249         if (pad_len == 0 || pad_len > real_iv_len) {
250                 g_set_error (error, NM_CRYPTO_ERROR,
251                              NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
252                              _("Failed to decrypt the private key: unexpected padding length."));
253                 goto out;
254         }
255
256         /* Validate tail padding; last byte is the padding size, and all pad bytes
257          * should contain the padding size.
258          */
259         for (i = pad_len; i > 0; i--) {
260                 if (output[data->len - i] != pad_len) {
261                         g_set_error (error, NM_CRYPTO_ERROR,
262                                      NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
263                                      _("Failed to decrypt the private key."));
264                         goto out;
265                 }
266         }
267
268         *out_len = decrypted_len;
269         success = TRUE;
270
271 out:
272         if (ctx)
273                 PK11_DestroyContext (ctx, PR_TRUE);
274         if (sym_key)
275                 PK11_FreeSymKey (sym_key);
276         if (sec_param)
277                 SECITEM_FreeItem (sec_param, PR_TRUE);
278         if (slot)
279                 PK11_FreeSlot (slot);
280
281         if (!success) {
282                 if (output) {
283                         /* Don't expose key material */
284                         memset (output, 0, data->len);
285                         g_free (output);
286                         output = NULL;
287                 }
288         }
289         return output;
290 }
291
292 char *
293 crypto_encrypt (const char *cipher,
294                 const GByteArray *data,
295                 const char *iv,
296                 gsize iv_len,
297                 const char *key,
298                 gsize key_len,
299                 gsize *out_len,
300                 GError **error)
301 {
302         SECStatus ret;
303         CK_MECHANISM_TYPE cipher_mech = CKM_DES3_CBC_PAD;
304         PK11SlotInfo *slot = NULL;
305         SECItem key_item = { .data = (unsigned char *) key, .len = key_len };
306         SECItem iv_item = { .data = (unsigned char *) iv, .len = iv_len };
307         PK11SymKey *sym_key = NULL;
308         SECItem *sec_param = NULL;
309         PK11Context *ctx = NULL;
310         unsigned char *output, *padded_buf;
311         gsize output_len;
312         int encrypted_len = 0, i;
313         gboolean success = FALSE;
314         gsize padded_buf_len, pad_len;
315
316         if (!strcmp (cipher, CIPHER_DES_EDE3_CBC))
317                 cipher_mech = CKM_DES3_CBC_PAD;
318         else if (!strcmp (cipher, CIPHER_AES_CBC))
319                 cipher_mech = CKM_AES_CBC_PAD;
320         else {
321                 g_set_error (error, NM_CRYPTO_ERROR,
322                              NM_CRYPTO_ERR_UNKNOWN_CIPHER,
323                              _("Private key cipher '%s' was unknown."),
324                              cipher);
325                 return NULL;
326         }
327
328         /* If data->len % ivlen == 0, then we add another complete block
329          * onto the end so that the decrypter knows there's padding.
330          */
331         pad_len = iv_len - (data->len % iv_len);
332         output_len = padded_buf_len = data->len + pad_len;
333         padded_buf = g_malloc0 (padded_buf_len);
334
335         memcpy (padded_buf, data->data, data->len);
336         for (i = 0; i < pad_len; i++)
337                 padded_buf[data->len + i] = (guint8) (pad_len & 0xFF);
338
339         output = g_malloc0 (output_len);
340
341         slot = PK11_GetBestSlot (cipher_mech, NULL);
342         if (!slot) {
343                 g_set_error (error, NM_CRYPTO_ERROR,
344                              NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
345                              _("Failed to initialize the encryption cipher slot."));
346                 goto out;
347         }
348
349         sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL);
350         if (!sym_key) {
351                 g_set_error (error, NM_CRYPTO_ERROR,
352                              NM_CRYPTO_ERR_CIPHER_SET_KEY_FAILED,
353                              _("Failed to set symmetric key for encryption."));
354                 goto out;
355         }
356
357         sec_param = PK11_ParamFromIV (cipher_mech, &iv_item);
358         if (!sec_param) {
359                 g_set_error (error, NM_CRYPTO_ERROR,
360                              NM_CRYPTO_ERR_CIPHER_SET_IV_FAILED,
361                              _("Failed to set IV for encryption."));
362                 goto out;
363         }
364
365         ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_ENCRYPT, sym_key, sec_param);
366         if (!ctx) {
367                 g_set_error (error, NM_CRYPTO_ERROR,
368                              NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
369                              _("Failed to initialize the encryption context."));
370                 goto out;
371         }
372
373         ret = PK11_CipherOp (ctx, output, &encrypted_len, output_len, padded_buf, padded_buf_len);
374         if (ret != SECSuccess) {
375                 g_set_error (error, NM_CRYPTO_ERROR,
376                              NM_CRYPTO_ERR_CIPHER_ENCRYPT_FAILED,
377                              _("Failed to encrypt: %d."),
378                              PORT_GetError ());
379                 goto out;
380         }
381
382         if (encrypted_len != output_len) {
383                 g_set_error (error, NM_CRYPTO_ERROR,
384                              NM_CRYPTO_ERR_CIPHER_ENCRYPT_FAILED,
385                              _("Unexpected amount of data after encrypting."));
386                 goto out;
387         }
388
389         *out_len = encrypted_len;
390         success = TRUE;
391
392 out:
393         if (ctx)
394                 PK11_DestroyContext (ctx, PR_TRUE);
395         if (sym_key)
396                 PK11_FreeSymKey (sym_key);
397         if (sec_param)
398                 SECITEM_FreeItem (sec_param, PR_TRUE);
399         if (slot)
400                 PK11_FreeSlot (slot);
401
402         memset (padded_buf, 0, padded_buf_len);
403         g_free (padded_buf);
404
405         if (!success) {
406                 memset (output, 0, output_len);
407                 g_free (output);
408                 output = NULL;
409         }
410         return (char *) output;
411 }
412
413 NMCryptoFileFormat
414 crypto_verify_cert (const unsigned char *data,
415                     gsize len,
416                     GError **error)
417 {
418         CERTCertificate *cert;
419
420         /* Try DER/PEM first */
421         cert = CERT_DecodeCertFromPackage ((char *) data, len);
422         if (!cert) {
423                 g_set_error (error, NM_CRYPTO_ERROR,
424                              NM_CRYPTO_ERR_CERT_FORMAT_INVALID,
425                              _("Couldn't decode certificate: %d"),
426                              PORT_GetError());
427                 return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
428         }
429
430         CERT_DestroyCertificate (cert);
431         return NM_CRYPTO_FILE_FORMAT_X509;
432 }
433
434 gboolean
435 crypto_verify_pkcs12 (const GByteArray *data,
436                       const char *password,
437                       GError **error)
438 {
439         SEC_PKCS12DecoderContext *p12ctx = NULL;
440         SECItem pw = { 0 };
441         PK11SlotInfo *slot = NULL;
442         SECStatus s;
443         char *ucs2_password;
444         glong ucs2_chars = 0;
445 #ifndef WORDS_BIGENDIAN
446         guint16 *p;
447 #endif /* WORDS_BIGENDIAN */
448
449         if (error)
450                 g_return_val_if_fail (*error == NULL, FALSE);
451
452         /* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do
453          * any conversions for us.
454          */
455         if (password && strlen (password)) {
456                 ucs2_password = (char *) g_utf8_to_utf16 (password, strlen (password), NULL, &ucs2_chars, NULL);
457                 if (!ucs2_password || !ucs2_chars) {
458                         g_set_error (error, NM_CRYPTO_ERROR,
459                                      NM_CRYPTO_ERR_INVALID_PASSWORD,
460                                      _("Couldn't convert password to UCS2: %d"),
461                                      PORT_GetError());
462                         return FALSE;
463                 }
464
465                 ucs2_chars *= 2;  /* convert # UCS2 characters -> bytes */
466                 pw.data = PORT_ZAlloc(ucs2_chars + 2);
467                 memcpy (pw.data, ucs2_password, ucs2_chars);
468                 pw.len = ucs2_chars + 2;  /* include terminating NULL */
469
470                 memset (ucs2_password, 0, ucs2_chars);
471                 g_free (ucs2_password);
472
473 #ifndef WORDS_BIGENDIAN
474                 for (p = (guint16 *) pw.data; p < (guint16 *) (pw.data + pw.len); p++)
475                         *p = GUINT16_SWAP_LE_BE (*p);
476 #endif /* WORDS_BIGENDIAN */
477         } else {
478                 /* NULL password */
479                 pw.data = NULL;
480                 pw.len = 0;
481         }
482
483         slot = PK11_GetInternalKeySlot();
484         p12ctx = SEC_PKCS12DecoderStart (&pw, slot, NULL, NULL, NULL, NULL, NULL, NULL);
485         if (!p12ctx) {
486                 g_set_error (error, NM_CRYPTO_ERROR,
487                              NM_CRYPTO_ERR_DECODE_FAILED,
488                              _("Couldn't initialize PKCS#12 decoder: %d"),
489                              PORT_GetError());
490                 goto error;
491         }
492
493         s = SEC_PKCS12DecoderUpdate (p12ctx, data->data, data->len);
494         if (s != SECSuccess) {
495                 g_set_error (error, NM_CRYPTO_ERROR,
496                              NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
497                              _("Couldn't decode PKCS#12 file: %d"),
498                              PORT_GetError());
499                 goto error;
500         }
501
502         s = SEC_PKCS12DecoderVerify (p12ctx);
503         if (s != SECSuccess) {
504                 g_set_error (error, NM_CRYPTO_ERROR,
505                              NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
506                              _("Couldn't verify PKCS#12 file: %d"),
507                              PORT_GetError());
508                 goto error;
509         }
510
511         SEC_PKCS12DecoderFinish (p12ctx);
512         SECITEM_ZfreeItem (&pw, PR_FALSE);
513         return TRUE;
514
515 error:
516         if (p12ctx)
517                 SEC_PKCS12DecoderFinish (p12ctx);
518
519         if (slot)
520                 PK11_FreeSlot(slot);
521
522         SECITEM_ZfreeItem (&pw, PR_FALSE);
523         return FALSE;
524 }
525
526 gboolean
527 crypto_verify_pkcs8 (const GByteArray *data,
528                      gboolean is_encrypted,
529                      const char *password,
530                      GError **error)
531 {
532         g_return_val_if_fail (data != NULL, FALSE);
533
534         /* NSS apparently doesn't do PKCS#8 natively, but you have to put the
535          * PKCS#8 key into a PKCS#12 file and import that??  So until we figure
536          * all that out, we can only assume the password is valid.
537          */
538         return TRUE;
539 }
540
541 gboolean
542 crypto_randomize (void *buffer, gsize buffer_len, GError **error)
543 {
544         SECStatus s;
545
546         s = PK11_GenerateRandom (buffer, buffer_len);
547         if (s != SECSuccess) {
548                 g_set_error_literal (error, NM_CRYPTO_ERROR,
549                                      NM_CRYPTO_ERR_RANDOMIZE_FAILED,
550                                      _("Could not generate random data."));
551                 return FALSE;
552         }
553         return TRUE;
554 }