Skip to content

Commit

Permalink
Add support for writing nssdbs
Browse files Browse the repository at this point in the history
NSSDBs have sepcific lists of attributes they deal with, and although
technically you can grow tables, we need to be able to handle attributes
that are NSS specific but may not care about in Kryoptic.

Handle initialization from scrath as well as writing data back to the
db.

At the same time we will need to filter out attributes Kryoptic may use
that are not supported by NSS, spin off more files to keep individual
files to reasonable sizes.

Signed-off-by: Simo Sorce <[email protected]>
  • Loading branch information
simo5 committed Nov 8, 2024
1 parent 9467874 commit ea8e15b
Show file tree
Hide file tree
Showing 3 changed files with 559 additions and 64 deletions.
247 changes: 247 additions & 0 deletions src/storage/nssdb/attrs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
// Copyright 2024 Simo Sorce
// See LICENSE.txt file for terms

use crate::interface::*;

const DEPRECATED_CKA_SECONDARY_AUTH: CK_ULONG = 512;
const DEPRECATED_CKA_AUTH_PIN_FLAGS: CK_ULONG = 513;

/* we use the CKA_NSS prefix instead of the preferred NSS_CKA one
* to allow for easy search in the NSS codebase */

/* off the regular NSS vendor offset for historical reasons */
const CKA_NSS_DB: CK_ATTRIBUTE_TYPE = 0xD5A0DB00;
const CKA_NSS_TRUST: CK_ATTRIBUTE_TYPE = 0x80000001;

/* NSS Vendor Offset attributes */
const NSS_VENDOR_OFFSET: CK_ULONG = CKA_VENDOR_DEFINED + 0x4E534350;
const CKA_NSS_URL: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 1;
const CKA_NSS_EMAIL: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 2;
const CKA_NSS_SMIME_INFO: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 3;
const CKA_NSS_SMIME_TIMESTAMP: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 4;
const CKA_NSS_PKCS8_SALT: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 5;
const CKA_NSS_PASSWORD_CHECK: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 6;
const CKA_NSS_EXPIRES: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 7;
const CKA_NSS_KRL: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 8;

const CKA_NSS_PQG_COUNTER: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 20;
const CKA_NSS_PQG_SEED: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 21;
const CKA_NSS_PQG_H: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 22;
const CKA_NSS_PQG_SEED_BITS: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 23;
const CKA_NSS_MODULE_SPEC: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 24;
const CKA_NSS_OVERRIDE_EXTENSIONS: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 25;

const CKA_NSS_SERVER_DISTRUST_AFTER: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 35;
const CKA_NSS_EMAIL_DISTRUST_AFTER: CK_ATTRIBUTE_TYPE = NSS_VENDOR_OFFSET + 36;

const NSS_VENDOR_TRUST: CK_ULONG = NSS_VENDOR_OFFSET + 0x2000;

const CKA_TRUST_DIGITAL_SIGNATURE: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 1;
const CKA_TRUST_NON_REPUDIATION: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 2;
const CKA_TRUST_KEY_ENCIPHERMENT: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 3;
const CKA_TRUST_DATA_ENCIPHERMENT: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 4;
const CKA_TRUST_KEY_AGREEMENT: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 5;
const CKA_TRUST_KEY_CERT_SIGN: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 6;
const CKA_TRUST_CRL_SIGN: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 7;
const CKA_TRUST_SERVER_AUTH: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 8;
const CKA_TRUST_CLIENT_AUTH: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 9;
const CKA_TRUST_CODE_SIGNING: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 10;
const CKA_TRUST_EMAIL_PROTECTION: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 11;
const CKA_TRUST_IPSEC_END_SYSTEM: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 12;
const CKA_TRUST_IPSEC_TUNNEL: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 13;
const CKA_TRUST_IPSEC_USER: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 14;
const CKA_TRUST_TIME_STAMPING: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 15;
const CKA_TRUST_STEP_UP_APPROVED: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 16;

const CKA_CERT_SHA1_HASH: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 100;
const CKA_CERT_MD5_HASH: CK_ATTRIBUTE_TYPE = NSS_VENDOR_TRUST + 101;

pub static NSS_KNOWN_ATTRIBUTES: [CK_ATTRIBUTE_TYPE; 119] = [
CKA_CLASS,
CKA_TOKEN,
CKA_PRIVATE,
CKA_LABEL,
CKA_APPLICATION,
CKA_VALUE,
CKA_OBJECT_ID,
CKA_CERTIFICATE_TYPE,
CKA_ISSUER,
CKA_SERIAL_NUMBER,
CKA_AC_ISSUER,
CKA_OWNER,
CKA_ATTR_TYPES,
CKA_TRUSTED,
CKA_CERTIFICATE_CATEGORY,
CKA_JAVA_MIDP_SECURITY_DOMAIN,
CKA_URL,
CKA_HASH_OF_SUBJECT_PUBLIC_KEY,
CKA_HASH_OF_ISSUER_PUBLIC_KEY,
CKA_CHECK_VALUE,
CKA_KEY_TYPE,
CKA_SUBJECT,
CKA_ID,
CKA_SENSITIVE,
CKA_ENCRYPT,
CKA_DECRYPT,
CKA_WRAP,
CKA_UNWRAP,
CKA_SIGN,
CKA_SIGN_RECOVER,
CKA_VERIFY,
CKA_VERIFY_RECOVER,
CKA_DERIVE,
CKA_START_DATE,
CKA_END_DATE,
CKA_MODULUS,
CKA_MODULUS_BITS,
CKA_PUBLIC_EXPONENT,
CKA_PRIVATE_EXPONENT,
CKA_PRIME_1,
CKA_PRIME_2,
CKA_EXPONENT_1,
CKA_EXPONENT_2,
CKA_COEFFICIENT,
CKA_PUBLIC_KEY_INFO,
CKA_PRIME,
CKA_SUBPRIME,
CKA_BASE,
CKA_PRIME_BITS,
CKA_SUB_PRIME_BITS,
CKA_VALUE_BITS,
CKA_VALUE_LEN,
CKA_EXTRACTABLE,
CKA_LOCAL,
CKA_NEVER_EXTRACTABLE,
CKA_ALWAYS_SENSITIVE,
CKA_KEY_GEN_MECHANISM,
CKA_MODIFIABLE,
CKA_EC_PARAMS,
CKA_EC_POINT,
DEPRECATED_CKA_SECONDARY_AUTH,
DEPRECATED_CKA_AUTH_PIN_FLAGS,
CKA_ALWAYS_AUTHENTICATE,
CKA_WRAP_WITH_TRUSTED,
CKA_HW_FEATURE_TYPE,
CKA_RESET_ON_INIT,
CKA_HAS_RESET,
CKA_PIXEL_X,
CKA_PIXEL_Y,
CKA_RESOLUTION,
CKA_CHAR_ROWS,
CKA_CHAR_COLUMNS,
CKA_COLOR,
CKA_BITS_PER_PIXEL,
CKA_CHAR_SETS,
CKA_ENCODING_METHODS,
CKA_MIME_TYPES,
CKA_MECHANISM_TYPE,
CKA_REQUIRED_CMS_ATTRIBUTES,
CKA_DEFAULT_CMS_ATTRIBUTES,
CKA_SUPPORTED_CMS_ATTRIBUTES,
CKA_WRAP_TEMPLATE,
CKA_UNWRAP_TEMPLATE,
CKA_NSS_TRUST,
CKA_NSS_URL,
CKA_NSS_EMAIL,
CKA_NSS_SMIME_INFO,
CKA_NSS_SMIME_TIMESTAMP,
CKA_NSS_PKCS8_SALT,
CKA_NSS_PASSWORD_CHECK,
CKA_NSS_EXPIRES,
CKA_NSS_KRL,
CKA_NSS_PQG_COUNTER,
CKA_NSS_PQG_SEED,
CKA_NSS_PQG_H,
CKA_NSS_PQG_SEED_BITS,
CKA_NSS_MODULE_SPEC,
CKA_NSS_OVERRIDE_EXTENSIONS,
CKA_NSS_SERVER_DISTRUST_AFTER,
CKA_NSS_EMAIL_DISTRUST_AFTER,
CKA_TRUST_DIGITAL_SIGNATURE,
CKA_TRUST_NON_REPUDIATION,
CKA_TRUST_KEY_ENCIPHERMENT,
CKA_TRUST_DATA_ENCIPHERMENT,
CKA_TRUST_KEY_AGREEMENT,
CKA_TRUST_KEY_CERT_SIGN,
CKA_TRUST_CRL_SIGN,
CKA_TRUST_SERVER_AUTH,
CKA_TRUST_CLIENT_AUTH,
CKA_TRUST_CODE_SIGNING,
CKA_TRUST_EMAIL_PROTECTION,
CKA_TRUST_IPSEC_END_SYSTEM,
CKA_TRUST_IPSEC_TUNNEL,
CKA_TRUST_IPSEC_USER,
CKA_TRUST_TIME_STAMPING,
CKA_TRUST_STEP_UP_APPROVED,
CKA_CERT_SHA1_HASH,
CKA_CERT_MD5_HASH,
CKA_NSS_DB,
];

/* NSS has a hardcoded list of attributes that are authenticated,
* some are vendor defined attributes */
pub static AUTHENTICATED_ATTRIBUTES: [CK_ATTRIBUTE_TYPE; 10] = [
CKA_MODULUS,
CKA_PUBLIC_EXPONENT,
CKA_CERT_SHA1_HASH,
CKA_CERT_MD5_HASH,
CKA_TRUST_SERVER_AUTH,
CKA_TRUST_CLIENT_AUTH,
CKA_TRUST_EMAIL_PROTECTION,
CKA_TRUST_CODE_SIGNING,
CKA_TRUST_STEP_UP_APPROVED,
CKA_NSS_OVERRIDE_EXTENSIONS,
];

static NSS_VENDOR_ATTRIBUTES: [CK_ATTRIBUTE_TYPE; 36] = [
CKA_NSS_TRUST,
CKA_NSS_URL,
CKA_NSS_EMAIL,
CKA_NSS_SMIME_INFO,
CKA_NSS_SMIME_TIMESTAMP,
CKA_NSS_PKCS8_SALT,
CKA_NSS_PASSWORD_CHECK,
CKA_NSS_EXPIRES,
CKA_NSS_KRL,
CKA_NSS_PQG_COUNTER,
CKA_NSS_PQG_SEED,
CKA_NSS_PQG_H,
CKA_NSS_PQG_SEED_BITS,
CKA_NSS_MODULE_SPEC,
CKA_NSS_OVERRIDE_EXTENSIONS,
CKA_NSS_SERVER_DISTRUST_AFTER,
CKA_NSS_EMAIL_DISTRUST_AFTER,
CKA_TRUST_DIGITAL_SIGNATURE,
CKA_TRUST_NON_REPUDIATION,
CKA_TRUST_KEY_ENCIPHERMENT,
CKA_TRUST_DATA_ENCIPHERMENT,
CKA_TRUST_KEY_AGREEMENT,
CKA_TRUST_KEY_CERT_SIGN,
CKA_TRUST_CRL_SIGN,
CKA_TRUST_SERVER_AUTH,
CKA_TRUST_CLIENT_AUTH,
CKA_TRUST_CODE_SIGNING,
CKA_TRUST_EMAIL_PROTECTION,
CKA_TRUST_IPSEC_END_SYSTEM,
CKA_TRUST_IPSEC_TUNNEL,
CKA_TRUST_IPSEC_USER,
CKA_TRUST_TIME_STAMPING,
CKA_TRUST_STEP_UP_APPROVED,
CKA_CERT_SHA1_HASH,
CKA_CERT_MD5_HASH,
CKA_NSS_DB,
];

pub fn ignore_attribute(attr: CK_ATTRIBUTE_TYPE) -> bool {
for a in &NSS_VENDOR_ATTRIBUTES {
if attr == *a {
return true;
}
}
if attr == DEPRECATED_CKA_SECONDARY_AUTH
|| attr == DEPRECATED_CKA_AUTH_PIN_FLAGS
{
return true;
}
return false;
}
112 changes: 97 additions & 15 deletions src/storage/nssdb/ci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ use crate::kasn1::oid::*;
use crate::kasn1::pkcs::*;
use crate::object::Object;
use crate::token::TokenFacilities;
use crate::CSPRNG;
use crate::{byte_ptr, sizeof, void_ptr};

pub const NSS_MP_PBE_ITERATION_COUNT: usize = 10000;

pub const PBMAC1_OID: asn1::ObjectIdentifier =
asn1::oid!(1, 2, 840, 113549, 1, 5, 14);

Expand Down Expand Up @@ -64,11 +67,16 @@ pub struct BrokenPBES2Params<'a> {
#[derive(
asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone, Debug,
)]
struct NSSEncryptedDataInfo<'a> {
pub struct NSSEncryptedDataInfo<'a> {
pub algorithm: Box<BrokenAlgorithmIdentifier<'a>>,
pub enc_or_sig_data: &'a [u8],
}

const HMAC_SHA_256_ALG: AlgorithmIdentifier<'_> = AlgorithmIdentifier {
oid: asn1::DefinedByMarker::marker(),
params: AlgorithmParameters::HmacWithSha256(Some(())),
};

fn pbkdf2_derive(
facilities: &TokenFacilities,
params: &PBKDF2Params,
Expand Down Expand Up @@ -141,6 +149,33 @@ fn aes_cbc_decrypt(
Ok(plain)
}

fn aes_cbc_encrypt(
facilities: &TokenFacilities,
key: &Object,
data: &[u8],
) -> Result<(Vec<u8>, Vec<u8>)> {
/* NSS has a Broken IV in the encoded data, so we need to adjust
* the IV to start with 0x04 0x0E which are thebytes that make a
* 16 bytes buffer "look like" a DER encoded OCTET_STRING. */
let mut iv: [u8; 16] = [0u8; 16];
iv[0] = 0x04;
iv[1] = 0x0e;
CSPRNG.with(|rng| rng.borrow_mut().generate_random(&mut iv[2..]))?;

let ck_mech = CK_MECHANISM {
mechanism: CKM_AES_CBC_PAD,
pParameter: void_ptr!(&iv),
ulParameterLen: CK_ULONG::try_from(iv.len())?,
};
let mech = facilities.mechanisms.get(CKM_AES_CBC_PAD)?;
let mut op = mech.encryption_new(&ck_mech, key)?;
let mut encdata = vec![0u8; op.encryption_len(data.len(), false)?];
let len = op.encrypt(data, &mut encdata)?;
encdata.resize(len, 0);

Ok((iv[2..].to_vec(), encdata))
}

pub fn decrypt_data(
facilities: &TokenFacilities,
secret: &[u8],
Expand Down Expand Up @@ -190,20 +225,67 @@ pub fn decrypt_data(
}
}

/* NSS has a hardcoded list of attributes that are authenticated,
* some are vendor defined attributes */
pub const AUTHENTICATED_ATTRIBUTES: [CK_ATTRIBUTE_TYPE; 2] = [
CKA_MODULUS,
CKA_PUBLIC_EXPONENT,
//CKA_CERT_SHA1_HASH,
//CKA_CERT_MD5_HASH,
//CKA_TRUST_SERVER_AUTH,
//CKA_TRUST_CLIENT_AUTH,
//CKA_TRUST_EMAIL_PROTECTION,
//CKA_TRUST_CODE_SIGNING,
//CKA_TRUST_STEP_UP_APPROVED,
//CKA_NSS_OVERRIDE_EXTENSIONS,
];
const ENC_KEY_LEN: CK_ULONG = 32;

pub fn encrypt_data<'a>(
facilities: &TokenFacilities,
secret: &'a [u8],
salt: &'a [u8],
iterations: usize,
data: &[u8],
) -> Result<Vec<u8>> {
let pbkdf2_params = PBKDF2Params {
salt: salt,
iteration_count: u64::try_from(iterations)?,
/* SHA2-256 length */
key_length: Some(u64::try_from(ENC_KEY_LEN)?),
prf: Box::new(HMAC_SHA_256_ALG),
};

/* compute key */
let ck_class: CK_OBJECT_CLASS = CKO_SECRET_KEY;
let ck_key_type: CK_KEY_TYPE = CKK_AES;
let ck_key_len: CK_ULONG = ENC_KEY_LEN;
let ck_true: CK_BBOOL = CK_TRUE;
let mut key_template = CkAttrs::with_capacity(5);
key_template.add_ulong(CKA_CLASS, &ck_class);
key_template.add_ulong(CKA_KEY_TYPE, &ck_key_type);
key_template.add_ulong(CKA_VALUE_LEN, &ck_key_len);
key_template.add_bool(CKA_DECRYPT, &ck_true);
key_template.add_bool(CKA_ENCRYPT, &ck_true);

let key = pbkdf2_derive(
facilities,
&pbkdf2_params,
secret,
key_template.as_slice(),
)?;
let (iv, enc_data) = aes_cbc_encrypt(facilities, &key, data)?;

let enc_params = BrokenAlgorithmIdentifier {
oid: asn1::DefinedByMarker::marker(),
params: BrokenAlgorithmParameters::Aes256Cbc(&iv),
};

let info = NSSEncryptedDataInfo {
algorithm: Box::new(BrokenAlgorithmIdentifier {
oid: asn1::DefinedByMarker::marker(),
params: BrokenAlgorithmParameters::Pbes2(BrokenPBES2Params {
key_derivation_func: Box::new(AlgorithmIdentifier {
oid: asn1::DefinedByMarker::marker(),
params: AlgorithmParameters::Pbkdf2(pbkdf2_params),
}),
encryption_scheme: Box::new(enc_params),
}),
}),
enc_or_sig_data: &enc_data,
};

match asn1::write_single(&info) {
Ok(der) => Ok(der),
Err(_) => Err(CKR_GENERAL_ERROR)?,
}
}

fn hmac_verify(
facilities: &TokenFacilities,
Expand Down
Loading

0 comments on commit ea8e15b

Please sign in to comment.