device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm-core / 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 #include "nm-errors.h"
38
39 static gboolean initialized = FALSE;
40
41 gboolean
42 crypto_init (GError **error)
43 {
44         SECStatus ret;
45
46         if (initialized)
47                 return TRUE;
48
49         PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 1);
50         ret = NSS_NoDB_Init (NULL);
51         if (ret != SECSuccess) {
52                 g_set_error (error, NM_CRYPTO_ERROR,
53                              NM_CRYPTO_ERROR_FAILED,
54                              _("Failed to initialize the crypto engine: %d."),
55                              PR_GetError ());
56                 PR_Cleanup ();
57                 return FALSE;
58         }
59
60         SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
61         SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
62         SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
63         SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
64         SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
65         SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
66         SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
67
68         initialized = TRUE;
69         return TRUE;
70 }
71
72 char *
73 crypto_decrypt (const char *cipher,
74                 int key_type,
75                 const guint8 *data,
76                 gsize data_len,
77                 const char *iv,
78                 const gsize iv_len,
79                 const char *key,
80                 const gsize key_len,
81                 gsize *out_len,
82                 GError **error)
83 {
84         char *output = NULL;
85         int decrypted_len = 0;
86         CK_MECHANISM_TYPE cipher_mech;
87         PK11SlotInfo *slot = NULL;
88         SECItem key_item;
89         PK11SymKey *sym_key = NULL;
90         SECItem *sec_param = NULL;
91         PK11Context *ctx = NULL;
92         SECStatus s;
93         gboolean success = FALSE;
94         unsigned int pad_len = 0, extra = 0;
95         guint32 i, real_iv_len = 0;
96
97         if (!crypto_init (error))
98                 return NULL;
99
100         if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
101                 cipher_mech = CKM_DES3_CBC_PAD;
102                 real_iv_len = 8;
103         } else if (!strcmp (cipher, CIPHER_DES_CBC)) {
104                 cipher_mech = CKM_DES_CBC_PAD;
105                 real_iv_len = 8;
106         } else if (!strcmp (cipher, CIPHER_AES_CBC)) {
107                 cipher_mech = CKM_AES_CBC_PAD;
108                 real_iv_len = 16;
109         } else {
110                 g_set_error (error, NM_CRYPTO_ERROR,
111                              NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
112                              _("Private key cipher '%s' was unknown."),
113                              cipher);
114                 return NULL;
115         }
116
117         if (iv_len < real_iv_len) {
118                 g_set_error (error, NM_CRYPTO_ERROR,
119                              NM_CRYPTO_ERROR_INVALID_DATA,
120                              _("Invalid IV length (must be at least %d)."),
121                              real_iv_len);
122                 return NULL;
123         }
124
125         output = g_malloc0 (data_len);
126
127         slot = PK11_GetBestSlot (cipher_mech, NULL);
128         if (!slot) {
129                 g_set_error (error, NM_CRYPTO_ERROR,
130                              NM_CRYPTO_ERROR_FAILED,
131                              _("Failed to initialize the decryption cipher slot."));
132                 goto out;
133         }
134
135         key_item.data = (unsigned char *) key;
136         key_item.len = key_len;
137         sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_DECRYPT, &key_item, NULL);
138         if (!sym_key) {
139                 g_set_error (error, NM_CRYPTO_ERROR,
140                              NM_CRYPTO_ERROR_DECRYPTION_FAILED,
141                              _("Failed to set symmetric key for decryption."));
142                 goto out;
143         }
144
145         key_item.data = (unsigned char *) iv;
146         key_item.len = real_iv_len;
147         sec_param = PK11_ParamFromIV (cipher_mech, &key_item);
148         if (!sec_param) {
149                 g_set_error (error, NM_CRYPTO_ERROR,
150                              NM_CRYPTO_ERROR_DECRYPTION_FAILED,
151                              _("Failed to set IV for decryption."));
152                 goto out;
153         }
154
155         ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_DECRYPT, sym_key, sec_param);
156         if (!ctx) {
157                 g_set_error (error, NM_CRYPTO_ERROR,
158                              NM_CRYPTO_ERROR_DECRYPTION_FAILED,
159                              _("Failed to initialize the decryption context."));
160                 goto out;
161         }
162
163         s = PK11_CipherOp (ctx,
164                            (unsigned char *) output,
165                            &decrypted_len,
166                            data_len,
167                            data,
168                            data_len);
169         if (s != SECSuccess) {
170                 g_set_error (error, NM_CRYPTO_ERROR,
171                              NM_CRYPTO_ERROR_DECRYPTION_FAILED,
172                              _("Failed to decrypt the private key: %d."),
173                              PORT_GetError ());
174                 goto out;
175         }
176
177         if (decrypted_len > data_len) {
178                 g_set_error (error, NM_CRYPTO_ERROR,
179                              NM_CRYPTO_ERROR_DECRYPTION_FAILED,
180                              _("Failed to decrypt the private key: decrypted data too large."));
181                 goto out;
182         }
183
184         s = PK11_DigestFinal (ctx,
185                               (unsigned char *) (output + decrypted_len),
186                               &extra,
187                               data_len - decrypted_len);
188         if (s != SECSuccess) {
189                 g_set_error (error, NM_CRYPTO_ERROR,
190                              NM_CRYPTO_ERROR_DECRYPTION_FAILED,
191                              _("Failed to finalize decryption of the private key: %d."),
192                              PORT_GetError ());
193                 goto out;
194         }
195         decrypted_len += extra;
196         pad_len = data_len - decrypted_len;
197
198         /* Check if the padding at the end of the decrypted data is valid */
199         if (pad_len == 0 || pad_len > real_iv_len) {
200                 g_set_error (error, NM_CRYPTO_ERROR,
201                              NM_CRYPTO_ERROR_DECRYPTION_FAILED,
202                              _("Failed to decrypt the private key: unexpected padding length."));
203                 goto out;
204         }
205
206         /* Validate tail padding; last byte is the padding size, and all pad bytes
207          * should contain the padding size.
208          */
209         for (i = pad_len; i > 0; i--) {
210                 if (output[data_len - i] != pad_len) {
211                         g_set_error (error, NM_CRYPTO_ERROR,
212                                      NM_CRYPTO_ERROR_DECRYPTION_FAILED,
213                                      _("Failed to decrypt the private key."));
214                         goto out;
215                 }
216         }
217
218         *out_len = decrypted_len;
219         success = TRUE;
220
221 out:
222         if (ctx)
223                 PK11_DestroyContext (ctx, PR_TRUE);
224         if (sym_key)
225                 PK11_FreeSymKey (sym_key);
226         if (sec_param)
227                 SECITEM_FreeItem (sec_param, PR_TRUE);
228         if (slot)
229                 PK11_FreeSlot (slot);
230
231         if (!success) {
232                 if (output) {
233                         /* Don't expose key material */
234                         memset (output, 0, data_len);
235                         g_free (output);
236                         output = NULL;
237                 }
238         }
239         return output;
240 }
241
242 char *
243 crypto_encrypt (const char *cipher,
244                 const guint8 *data,
245                 gsize data_len,
246                 const char *iv,
247                 gsize iv_len,
248                 const char *key,
249                 gsize key_len,
250                 gsize *out_len,
251                 GError **error)
252 {
253         SECStatus ret;
254         CK_MECHANISM_TYPE cipher_mech = CKM_DES3_CBC_PAD;
255         PK11SlotInfo *slot = NULL;
256         SECItem key_item = { .data = (unsigned char *) key, .len = key_len };
257         SECItem iv_item = { .data = (unsigned char *) iv, .len = iv_len };
258         PK11SymKey *sym_key = NULL;
259         SECItem *sec_param = NULL;
260         PK11Context *ctx = NULL;
261         unsigned char *output, *padded_buf;
262         gsize output_len;
263         int encrypted_len = 0, i;
264         gboolean success = FALSE;
265         gsize padded_buf_len, pad_len;
266
267         if (!crypto_init (error))
268                 return NULL;
269
270         if (!strcmp (cipher, CIPHER_DES_EDE3_CBC))
271                 cipher_mech = CKM_DES3_CBC_PAD;
272         else if (!strcmp (cipher, CIPHER_AES_CBC))
273                 cipher_mech = CKM_AES_CBC_PAD;
274         else {
275                 g_set_error (error, NM_CRYPTO_ERROR,
276                              NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
277                              _("Private key cipher '%s' was unknown."),
278                              cipher);
279                 return NULL;
280         }
281
282         /* If data->len % ivlen == 0, then we add another complete block
283          * onto the end so that the decrypter knows there's padding.
284          */
285         pad_len = iv_len - (data_len % iv_len);
286         output_len = padded_buf_len = data_len + pad_len;
287         padded_buf = g_malloc0 (padded_buf_len);
288
289         memcpy (padded_buf, data, data_len);
290         for (i = 0; i < pad_len; i++)
291                 padded_buf[data_len + i] = (guint8) (pad_len & 0xFF);
292
293         output = g_malloc0 (output_len);
294
295         slot = PK11_GetBestSlot (cipher_mech, NULL);
296         if (!slot) {
297                 g_set_error (error, NM_CRYPTO_ERROR,
298                              NM_CRYPTO_ERROR_FAILED,
299                              _("Failed to initialize the encryption cipher slot."));
300                 goto out;
301         }
302
303         sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL);
304         if (!sym_key) {
305                 g_set_error (error, NM_CRYPTO_ERROR,
306                              NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
307                              _("Failed to set symmetric key for encryption."));
308                 goto out;
309         }
310
311         sec_param = PK11_ParamFromIV (cipher_mech, &iv_item);
312         if (!sec_param) {
313                 g_set_error (error, NM_CRYPTO_ERROR,
314                              NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
315                              _("Failed to set IV for encryption."));
316                 goto out;
317         }
318
319         ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_ENCRYPT, sym_key, sec_param);
320         if (!ctx) {
321                 g_set_error (error, NM_CRYPTO_ERROR,
322                              NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
323                              _("Failed to initialize the encryption context."));
324                 goto out;
325         }
326
327         ret = PK11_CipherOp (ctx, output, &encrypted_len, output_len, padded_buf, padded_buf_len);
328         if (ret != SECSuccess) {
329                 g_set_error (error, NM_CRYPTO_ERROR,
330                              NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
331                              _("Failed to encrypt: %d."),
332                              PORT_GetError ());
333                 goto out;
334         }
335
336         if (encrypted_len != output_len) {
337                 g_set_error (error, NM_CRYPTO_ERROR,
338                              NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
339                              _("Unexpected amount of data after encrypting."));
340                 goto out;
341         }
342
343         *out_len = encrypted_len;
344         success = TRUE;
345
346 out:
347         if (ctx)
348                 PK11_DestroyContext (ctx, PR_TRUE);
349         if (sym_key)
350                 PK11_FreeSymKey (sym_key);
351         if (sec_param)
352                 SECITEM_FreeItem (sec_param, PR_TRUE);
353         if (slot)
354                 PK11_FreeSlot (slot);
355
356         memset (padded_buf, 0, padded_buf_len);
357         g_free (padded_buf);
358
359         if (!success) {
360                 memset (output, 0, output_len);
361                 g_free (output);
362                 output = NULL;
363         }
364         return (char *) output;
365 }
366
367 NMCryptoFileFormat
368 crypto_verify_cert (const unsigned char *data,
369                     gsize len,
370                     GError **error)
371 {
372         CERTCertificate *cert;
373
374         if (!crypto_init (error))
375                 return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
376
377         /* Try DER/PEM first */
378         cert = CERT_DecodeCertFromPackage ((char *) data, len);
379         if (!cert) {
380                 g_set_error (error, NM_CRYPTO_ERROR,
381                              NM_CRYPTO_ERROR_INVALID_DATA,
382                              _("Couldn't decode certificate: %d"),
383                              PORT_GetError());
384                 return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
385         }
386
387         CERT_DestroyCertificate (cert);
388         return NM_CRYPTO_FILE_FORMAT_X509;
389 }
390
391 gboolean
392 crypto_verify_pkcs12 (const guint8 *data,
393                       gsize data_len,
394                       const char *password,
395                       GError **error)
396 {
397         SEC_PKCS12DecoderContext *p12ctx = NULL;
398         SECItem pw = { 0 };
399         PK11SlotInfo *slot = NULL;
400         SECStatus s;
401         gunichar2 *ucs2_password;
402         glong ucs2_chars = 0;
403 #ifndef WORDS_BIGENDIAN
404         guint16 *p;
405 #endif /* WORDS_BIGENDIAN */
406
407         if (error)
408                 g_return_val_if_fail (*error == NULL, FALSE);
409
410         if (!crypto_init (error))
411                 return FALSE;
412
413         /* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do
414          * any conversions for us.
415          */
416         if (password && *password) {
417                 if (!g_utf8_validate (password, -1, NULL)) {
418                         g_set_error (error, NM_CRYPTO_ERROR,
419                                      NM_CRYPTO_ERROR_INVALID_PASSWORD,
420                                      _("Password must be UTF-8"));
421                         return FALSE;
422                 }
423                 ucs2_password = g_utf8_to_utf16 (password, strlen (password), NULL, &ucs2_chars, NULL);
424                 /* Can't fail if g_utf8_validate() succeeded */
425                 g_return_val_if_fail (ucs2_password != NULL && ucs2_chars != 0, FALSE);
426
427                 ucs2_chars *= 2;  /* convert # UCS2 characters -> bytes */
428                 pw.data = PORT_ZAlloc(ucs2_chars + 2);
429                 memcpy (pw.data, ucs2_password, ucs2_chars);
430                 pw.len = ucs2_chars + 2;  /* include terminating NULL */
431
432                 memset (ucs2_password, 0, ucs2_chars);
433                 g_free (ucs2_password);
434
435 #ifndef WORDS_BIGENDIAN
436                 for (p = (guint16 *) pw.data; p < (guint16 *) (pw.data + pw.len); p++)
437                         *p = GUINT16_SWAP_LE_BE (*p);
438 #endif /* WORDS_BIGENDIAN */
439         } else {
440                 /* NULL password */
441                 pw.data = NULL;
442                 pw.len = 0;
443         }
444
445         slot = PK11_GetInternalKeySlot();
446         p12ctx = SEC_PKCS12DecoderStart (&pw, slot, NULL, NULL, NULL, NULL, NULL, NULL);
447         if (!p12ctx) {
448                 g_set_error (error, NM_CRYPTO_ERROR,
449                              NM_CRYPTO_ERROR_FAILED,
450                              _("Couldn't initialize PKCS#12 decoder: %d"),
451                              PORT_GetError());
452                 goto error;
453         }
454
455         s = SEC_PKCS12DecoderUpdate (p12ctx, (guint8 *)data, data_len);
456         if (s != SECSuccess) {
457                 g_set_error (error, NM_CRYPTO_ERROR,
458                              NM_CRYPTO_ERROR_INVALID_DATA,
459                              _("Couldn't decode PKCS#12 file: %d"),
460                              PORT_GetError());
461                 goto error;
462         }
463
464         s = SEC_PKCS12DecoderVerify (p12ctx);
465         if (s != SECSuccess) {
466                 g_set_error (error, NM_CRYPTO_ERROR,
467                              NM_CRYPTO_ERROR_DECRYPTION_FAILED,
468                              _("Couldn't verify PKCS#12 file: %d"),
469                              PORT_GetError());
470                 goto error;
471         }
472
473         SEC_PKCS12DecoderFinish (p12ctx);
474         SECITEM_ZfreeItem (&pw, PR_FALSE);
475         return TRUE;
476
477 error:
478         if (p12ctx)
479                 SEC_PKCS12DecoderFinish (p12ctx);
480
481         if (slot)
482                 PK11_FreeSlot(slot);
483
484         SECITEM_ZfreeItem (&pw, PR_FALSE);
485         return FALSE;
486 }
487
488 gboolean
489 crypto_verify_pkcs8 (const guint8 *data,
490                      gsize data_len,
491                      gboolean is_encrypted,
492                      const char *password,
493                      GError **error)
494 {
495         g_return_val_if_fail (data != NULL, FALSE);
496
497         if (!crypto_init (error))
498                 return FALSE;
499
500         /* NSS apparently doesn't do PKCS#8 natively, but you have to put the
501          * PKCS#8 key into a PKCS#12 file and import that??  So until we figure
502          * all that out, we can only assume the password is valid.
503          */
504         return TRUE;
505 }
506
507 gboolean
508 crypto_randomize (void *buffer, gsize buffer_len, GError **error)
509 {
510         SECStatus s;
511
512         if (!crypto_init (error))
513                 return FALSE;
514
515         s = PK11_GenerateRandom (buffer, buffer_len);
516         if (s != SECSuccess) {
517                 g_set_error_literal (error, NM_CRYPTO_ERROR,
518                                      NM_CRYPTO_ERROR_FAILED,
519                                      _("Could not generate random data."));
520                 return FALSE;
521         }
522         return TRUE;
523 }