1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
4 * Dan Williams <dcbw@redhat.com>
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.
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.
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.
21 * Copyright 2007 - 2009 Red Hat, Inc.
24 #include "nm-default.h"
37 #include "nm-errors.h"
39 static gboolean initialized = FALSE;
42 crypto_init (GError **error)
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."),
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);
73 crypto_decrypt (const char *cipher,
85 int decrypted_len = 0;
86 CK_MECHANISM_TYPE cipher_mech;
87 PK11SlotInfo *slot = NULL;
89 PK11SymKey *sym_key = NULL;
90 SECItem *sec_param = NULL;
91 PK11Context *ctx = NULL;
93 gboolean success = FALSE;
94 unsigned int pad_len = 0, extra = 0;
95 guint32 i, real_iv_len = 0;
97 if (!crypto_init (error))
100 if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
101 cipher_mech = CKM_DES3_CBC_PAD;
103 } else if (!strcmp (cipher, CIPHER_DES_CBC)) {
104 cipher_mech = CKM_DES_CBC_PAD;
106 } else if (!strcmp (cipher, CIPHER_AES_CBC)) {
107 cipher_mech = CKM_AES_CBC_PAD;
110 g_set_error (error, NM_CRYPTO_ERROR,
111 NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
112 _("Private key cipher '%s' was unknown."),
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)."),
125 output = g_malloc0 (data_len);
127 slot = PK11_GetBestSlot (cipher_mech, NULL);
129 g_set_error (error, NM_CRYPTO_ERROR,
130 NM_CRYPTO_ERROR_FAILED,
131 _("Failed to initialize the decryption cipher slot."));
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);
139 g_set_error (error, NM_CRYPTO_ERROR,
140 NM_CRYPTO_ERROR_DECRYPTION_FAILED,
141 _("Failed to set symmetric key for decryption."));
145 key_item.data = (unsigned char *) iv;
146 key_item.len = real_iv_len;
147 sec_param = PK11_ParamFromIV (cipher_mech, &key_item);
149 g_set_error (error, NM_CRYPTO_ERROR,
150 NM_CRYPTO_ERROR_DECRYPTION_FAILED,
151 _("Failed to set IV for decryption."));
155 ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_DECRYPT, sym_key, sec_param);
157 g_set_error (error, NM_CRYPTO_ERROR,
158 NM_CRYPTO_ERROR_DECRYPTION_FAILED,
159 _("Failed to initialize the decryption context."));
163 s = PK11_CipherOp (ctx,
164 (unsigned char *) output,
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."),
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."));
184 s = PK11_DigestFinal (ctx,
185 (unsigned char *) (output + decrypted_len),
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."),
195 decrypted_len += extra;
196 pad_len = data_len - decrypted_len;
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."));
206 /* Validate tail padding; last byte is the padding size, and all pad bytes
207 * should contain the padding size.
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."));
218 *out_len = decrypted_len;
223 PK11_DestroyContext (ctx, PR_TRUE);
225 PK11_FreeSymKey (sym_key);
227 SECITEM_FreeItem (sec_param, PR_TRUE);
229 PK11_FreeSlot (slot);
233 /* Don't expose key material */
234 memset (output, 0, data_len);
243 crypto_encrypt (const char *cipher,
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;
263 int encrypted_len = 0, i;
264 gboolean success = FALSE;
265 gsize padded_buf_len, pad_len;
267 if (!crypto_init (error))
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;
275 g_set_error (error, NM_CRYPTO_ERROR,
276 NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
277 _("Private key cipher '%s' was unknown."),
282 /* If data->len % ivlen == 0, then we add another complete block
283 * onto the end so that the decrypter knows there's padding.
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);
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);
293 output = g_malloc0 (output_len);
295 slot = PK11_GetBestSlot (cipher_mech, NULL);
297 g_set_error (error, NM_CRYPTO_ERROR,
298 NM_CRYPTO_ERROR_FAILED,
299 _("Failed to initialize the encryption cipher slot."));
303 sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL);
305 g_set_error (error, NM_CRYPTO_ERROR,
306 NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
307 _("Failed to set symmetric key for encryption."));
311 sec_param = PK11_ParamFromIV (cipher_mech, &iv_item);
313 g_set_error (error, NM_CRYPTO_ERROR,
314 NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
315 _("Failed to set IV for encryption."));
319 ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_ENCRYPT, sym_key, sec_param);
321 g_set_error (error, NM_CRYPTO_ERROR,
322 NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
323 _("Failed to initialize the encryption context."));
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."),
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."));
343 *out_len = encrypted_len;
348 PK11_DestroyContext (ctx, PR_TRUE);
350 PK11_FreeSymKey (sym_key);
352 SECITEM_FreeItem (sec_param, PR_TRUE);
354 PK11_FreeSlot (slot);
356 memset (padded_buf, 0, padded_buf_len);
360 memset (output, 0, output_len);
364 return (char *) output;
368 crypto_verify_cert (const unsigned char *data,
372 CERTCertificate *cert;
374 if (!crypto_init (error))
375 return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
377 /* Try DER/PEM first */
378 cert = CERT_DecodeCertFromPackage ((char *) data, len);
380 g_set_error (error, NM_CRYPTO_ERROR,
381 NM_CRYPTO_ERROR_INVALID_DATA,
382 _("Couldn't decode certificate: %d"),
384 return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
387 CERT_DestroyCertificate (cert);
388 return NM_CRYPTO_FILE_FORMAT_X509;
392 crypto_verify_pkcs12 (const guint8 *data,
394 const char *password,
397 SEC_PKCS12DecoderContext *p12ctx = NULL;
399 PK11SlotInfo *slot = NULL;
401 gunichar2 *ucs2_password;
402 glong ucs2_chars = 0;
403 #ifndef WORDS_BIGENDIAN
405 #endif /* WORDS_BIGENDIAN */
408 g_return_val_if_fail (*error == NULL, FALSE);
410 if (!crypto_init (error))
413 /* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do
414 * any conversions for us.
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"));
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);
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 */
432 memset (ucs2_password, 0, ucs2_chars);
433 g_free (ucs2_password);
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 */
445 slot = PK11_GetInternalKeySlot();
446 p12ctx = SEC_PKCS12DecoderStart (&pw, slot, NULL, NULL, NULL, NULL, NULL, NULL);
448 g_set_error (error, NM_CRYPTO_ERROR,
449 NM_CRYPTO_ERROR_FAILED,
450 _("Couldn't initialize PKCS#12 decoder: %d"),
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"),
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"),
473 SEC_PKCS12DecoderFinish (p12ctx);
474 SECITEM_ZfreeItem (&pw, PR_FALSE);
479 SEC_PKCS12DecoderFinish (p12ctx);
484 SECITEM_ZfreeItem (&pw, PR_FALSE);
489 crypto_verify_pkcs8 (const guint8 *data,
491 gboolean is_encrypted,
492 const char *password,
495 g_return_val_if_fail (data != NULL, FALSE);
497 if (!crypto_init (error))
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.
508 crypto_randomize (void *buffer, gsize buffer_len, GError **error)
512 if (!crypto_init (error))
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."));