diff options
author | lloyd <[email protected]> | 2006-06-03 06:10:36 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2006-06-03 06:10:36 +0000 |
commit | 25aaeee23fd952525eadabea43b1c4e8a2cf1b02 (patch) | |
tree | f39ce2525b73734e289b4b591093c6b2436b7007 /misc | |
parent | 6f75c2fe6e536c0192f3acb00c84edbc762127da (diff) |
Add the (very old) CMS | S/MIME support code to misc/cms
Diffstat (limited to 'misc')
-rw-r--r-- | misc/cms/cms_algo.cpp | 141 | ||||
-rw-r--r-- | misc/cms/cms_comp.cpp | 98 | ||||
-rw-r--r-- | misc/cms/cms_dalg.cpp | 267 | ||||
-rw-r--r-- | misc/cms/cms_dec.cpp | 114 | ||||
-rw-r--r-- | misc/cms/cms_dec.h | 63 | ||||
-rw-r--r-- | misc/cms/cms_ealg.cpp | 369 | ||||
-rw-r--r-- | misc/cms/cms_enc.cpp | 87 | ||||
-rw-r--r-- | misc/cms/cms_enc.h | 70 | ||||
-rw-r--r-- | misc/cms/readme.txt | 24 | ||||
-rw-r--r-- | misc/cms/tests/cacert.pem | 15 | ||||
-rw-r--r-- | misc/cms/tests/cms_dec.cpp | 111 | ||||
-rw-r--r-- | misc/cms/tests/cms_enc.cpp | 46 | ||||
-rw-r--r-- | misc/cms/tests/int_ca.pem | 18 | ||||
-rw-r--r-- | misc/cms/tests/mycert.pem | 19 | ||||
-rw-r--r-- | misc/cms/tests/mycert2.pem | 25 | ||||
-rw-r--r-- | misc/cms/tests/mykey.pem | 17 | ||||
-rw-r--r-- | misc/cms/tests/mykey2.pem | 11 | ||||
-rw-r--r-- | misc/cms/tests/yourcert.pem | 18 |
18 files changed, 1513 insertions, 0 deletions
diff --git a/misc/cms/cms_algo.cpp b/misc/cms/cms_algo.cpp new file mode 100644 index 000000000..8143bbe5c --- /dev/null +++ b/misc/cms/cms_algo.cpp @@ -0,0 +1,141 @@ +/************************************************* +* CMS Algorithm Specific Code Source File * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#include <botan/cms_enc.h> +#include <botan/der_enc.h> +#include <botan/lookup.h> +#include <botan/filters.h> +#include <botan/rng.h> +#include <botan/rc2.h> + +namespace Botan { + +namespace { + +/************************************************* +* Wrap a key as specified in RFC 3217 * +*************************************************/ +SecureVector<byte> do_rfc3217_wrap(const std::string& cipher, + const SymmetricKey& kek, + const SecureVector<byte>& input) + { + class Flip_Bytes : public Filter + { + public: + void write(const byte data[], u32bit length) + { + buf.append(data, length); + } + void end_msg() + { + for(u32bit j = 0; j != buf.size(); j++) + send(buf[buf.size()-j-1]); + buf.destroy(); + } + Flip_Bytes(const SecureVector<byte>& prefix) { buf.append(prefix); } + private: + SecureVector<byte> buf; + }; + + if(block_size_of(cipher) != 8) + throw Encoding_Error("do_rfc3217_wrap: Bad cipher: " + cipher); + + Pipe icv(new Hash_Filter("SHA-160", 8)); + icv.process_msg(input); + + InitializationVector iv(8); + InitializationVector fixed("4ADDA22C79E82105"); + + Pipe pipe(get_cipher(cipher + "/CBC/NoPadding", kek, iv, ENCRYPTION), + new Flip_Bytes(iv.copy()), + get_cipher(cipher + "/CBC/NoPadding", kek, fixed, ENCRYPTION)); + pipe.start_msg(); + pipe.write(input); + pipe.write(icv.read_all()); + pipe.end_msg(); + return pipe.read_all(); + } + +} + +/************************************************* +* Wrap a CEK with a KEK * +*************************************************/ +SecureVector<byte> CMS_Encoder::wrap_key(const std::string& cipher, + const SymmetricKey& cek, + const SymmetricKey& kek) + { + if(cipher == "TripleDES") + { + SymmetricKey cek_parity = cek; + cek_parity.set_odd_parity(); + return do_rfc3217_wrap(cipher, kek, cek_parity.copy()); + } + else if(cipher == "RC2" || cipher == "CAST-128") + { + if(kek.length() != 16) + throw Encoding_Error("CMS: 128-bit KEKs must be used with " + cipher); + + SecureVector<byte> lcekpad; + lcekpad.append((byte)cek.length()); + lcekpad.append(cek.copy()); + while(lcekpad.size() % 8) + lcekpad.append(Global_RNG::random(Nonce)); + return do_rfc3217_wrap(cipher, kek, lcekpad); + } + else + throw Invalid_Argument("CMS_Encoder::wrap: Unknown cipher " + cipher); + } + +/************************************************* +* Encode the parameters for an encryption algo * +*************************************************/ +SecureVector<byte> CMS_Encoder::encode_params(const std::string& cipher, + const SymmetricKey& key, + const InitializationVector& iv) + { + DER_Encoder encoder; + + if(cipher == "RC2") + { + encoder.start_sequence(); + DER::encode(encoder, RC2::EKB_code(8*key.length())); + DER::encode(encoder, iv.copy(), OCTET_STRING); + encoder.end_sequence(); + } + else if(cipher == "CAST-128") + { + encoder.start_sequence(); + DER::encode(encoder, iv.copy(), OCTET_STRING); + DER::encode(encoder, 8*key.length()); + encoder.end_sequence(); + } + else + DER::encode(encoder, iv.copy(), OCTET_STRING); + + return encoder.get_contents(); + } + +/************************************************* +* Generate a CEK or KEK for the cipher * +*************************************************/ +SymmetricKey CMS_Encoder::setup_key(const std::string& cipher) + { + u32bit keysize = 0; + + if(cipher == "TripleDES") keysize = 24; + if(cipher == "RC2") keysize = 16; + if(cipher == "CAST-128") keysize = 16; + + if(keysize == 0) + throw Invalid_Argument("CMS: Cannot encrypt with cipher " + cipher); + + SymmetricKey key(keysize); + if(cipher == "DES" || cipher == "TripleDES") + key.set_odd_parity(); + return key; + } + +} diff --git a/misc/cms/cms_comp.cpp b/misc/cms/cms_comp.cpp new file mode 100644 index 000000000..8d120c172 --- /dev/null +++ b/misc/cms/cms_comp.cpp @@ -0,0 +1,98 @@ +/************************************************* +* CMS Compression Source File * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#include <botan/cms_enc.h> +#include <botan/cms_dec.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/oids.h> +#include <botan/pipe.h> + +#if defined(BOTAN_EXT_COMPRESSOR_ZLIB) + #include <botan/zlib.h> + #define HAVE_ZLIB 1 +#else + #define HAVE_ZLIB 0 +#endif + +namespace Botan { + +/************************************************* +* Compress a message * +*************************************************/ +void CMS_Encoder::compress(const std::string& algo) + { + if(!CMS_Encoder::can_compress_with(algo)) + throw Invalid_Argument("CMS_Encoder: Cannot compress with " + algo); + + Filter* compressor = 0; + +#if HAVE_ZLIB + if(algo == "Zlib") compressor = new Zlib_Compression; +#endif + + if(compressor == 0) + throw Internal_Error("CMS: Couldn't get ahold of a compressor"); + + Pipe pipe(compressor); + pipe.process_msg(data); + SecureVector<byte> compressed = pipe.read_all(); + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, 0); + DER::encode(encoder, AlgorithmIdentifier("Compression." + algo, false)); + encoder.add_raw_octets(make_econtent(compressed, type)); + encoder.end_sequence(); + + add_layer("CMS.CompressedData", encoder); + } + +/************************************************* +* See if the named compression algo is available * +*************************************************/ +bool CMS_Encoder::can_compress_with(const std::string& algo) + { + if(HAVE_ZLIB && algo == "Zlib") + return true; + return false; + } + +/************************************************* +* Decompress a message * +*************************************************/ +void CMS_Decoder::decompress(BER_Decoder& decoder) + { + u32bit version; + AlgorithmIdentifier comp_algo; + + BER_Decoder comp_info = BER::get_subsequence(decoder); + BER::decode(comp_info, version); + if(version != 0) + throw Decoding_Error("CMS: Unknown version for CompressedData"); + BER::decode(comp_info, comp_algo); + read_econtent(comp_info); + comp_info.verify_end(); + + Filter* decompressor = 0; + + info = comp_algo.oid.as_string(); +#if HAVE_ZLIB + if(comp_algo.oid == OIDS::lookup("Compression.Zlib")) + { + decompressor = new Zlib_Decompression; + info = "Zlib"; + } +#endif + + if(!decompressor) + status = FAILURE; + + Pipe pipe(decompressor); + pipe.process_msg(data); + data = pipe.read_all(); + } + +} diff --git a/misc/cms/cms_dalg.cpp b/misc/cms/cms_dalg.cpp new file mode 100644 index 000000000..aed19e1b1 --- /dev/null +++ b/misc/cms/cms_dalg.cpp @@ -0,0 +1,267 @@ +/************************************************* +* CMS Decoding Operations Source File * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#include <botan/cms_dec.h> +#include <botan/ber_dec.h> +#include <botan/oids.h> +#include <botan/lookup.h> +#include <botan/look_pk.h> +#include <memory> + +namespace Botan { + +namespace { + +/************************************************* +* Compute the hash of some content * +*************************************************/ +SecureVector<byte> hash_of(const SecureVector<byte>& content, + const AlgorithmIdentifier& hash_algo, + std::string& hash_name) + { + hash_name = OIDS::lookup(hash_algo.oid); + std::auto_ptr<HashFunction> hash_fn(get_hash(hash_name)); + return hash_fn->process(content); + } + +/************************************************* +* Find a cert based on SignerIdentifier * +*************************************************/ +std::vector<X509_Certificate> get_cert(BER_Decoder& signer_info, + X509_Store& store) + { + BER_Object id = signer_info.get_next_object(); + + std::vector<X509_Certificate> found; + + if(id.type_tag == SEQUENCE && id.class_tag == CONSTRUCTED) + { + X509_DN issuer; + BigInt serial; + BER_Decoder iands(id.value); + BER::decode(iands, issuer); + BER::decode(iands, serial); + + found = X509_Store_Search::by_iands(store, issuer, + BigInt::encode(serial)); + } + else if(id.type_tag == 0 && id.class_tag == CONSTRUCTED) + found = X509_Store_Search::by_SKID(store, id.value); + else + throw Decoding_Error("CMS: Unknown tag for cert identifier"); + + // verify cert if found + + if(found.size() > 1) + throw Internal_Error("CMS: Found more than one match in get_cert"); + return found; + } + +/************************************************* +* Read OriginatorInfo * +*************************************************/ +void read_orig_info(BER_Decoder& info, X509_Store& store) + { + BER_Object next = info.get_next_object(); + + if(next.type_tag == 0 && + next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + { + DataSource_Memory certs(next.value); + while(!certs.end_of_data()) + { + // FIXME: can be attribute certs too + // FIXME: DoS? + X509_Certificate cert(certs); + store.add_cert(cert); + } + next = info.get_next_object(); + } + if(next.type_tag == 1 && + next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + { + DataSource_Memory crls(next.value); + while(!crls.end_of_data()) + { + // FIXME: DoS? + X509_CRL crl(crls); + store.add_crl(crl); + } + next = info.get_next_object(); + } + info.push_back(next); + } + +/************************************************* +* Decode any Attributes, and check type * +*************************************************/ +SecureVector<byte> decode_attributes(BER_Decoder& ber, const OID& type, + bool& bad_attributes) + { + BER_Object obj = ber.get_next_object(); + SecureVector<byte> digest; + + bool got_digest = false; + bool got_content_type = false; + + if(obj.type_tag == 0 && + obj.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + ber.push_back(obj); + else + { + BER_Decoder attributes(obj.value); + while(attributes.more_items()) + { + Attribute attr; + BER::decode(attributes, attr); + BER_Decoder attr_value(attr.parameters); + + if(attr.oid == OIDS::lookup("PKCS9.MessageDigest")) + { + got_digest = true; + BER::decode(attr_value, digest, OCTET_STRING); + } + else if(attr.oid == OIDS::lookup("PKCS9.ContentType")) + { + got_content_type = true; + OID inner_type; + BER::decode(attr_value, inner_type); + if(inner_type != type) + bad_attributes = true; + } + else + throw Decoding_Error("Unknown/unhandled CMS attribute found: " + + OIDS::lookup(attr.oid)); + } + + if(!got_digest || !got_content_type) + bad_attributes = true; + } + + return digest; + } + +} + +/************************************************* +* Decode this layer of CMS encoding * +*************************************************/ +void CMS_Decoder::decode_layer() + { + try { + if(status == FAILURE) + throw Invalid_State("CMS: Decoder is in FAILURE state"); + + status = GOOD; + info = ""; + + type = next_type; + + if(type == OIDS::lookup("CMS.DataContent")) + return; + + BER_Decoder decoder(data); + if(type == OIDS::lookup("CMS.CompressedData")) + decompress(decoder); + else if(type == OIDS::lookup("CMS.DigestedData")) + { + u32bit version; + AlgorithmIdentifier hash_algo; + SecureVector<byte> digest; + + BER_Decoder hash_info = BER::get_subsequence(decoder); + BER::decode(hash_info, version); + if(version != 0 && version != 2) + throw Decoding_Error("CMS: Unknown version for DigestedData"); + BER::decode(hash_info, hash_algo); + read_econtent(hash_info); + BER::decode(hash_info, digest, OCTET_STRING); + hash_info.verify_end(); + + if(digest != hash_of(data, hash_algo, info)) + status = BAD; + } + else if(type == OIDS::lookup("CMS.SignedData")) + { +#if 1 + throw Exception("FIXME: not implemented"); +#else + u32bit version; + + BER_Decoder sig_info = BER::get_subsequence(decoder); + BER::decode(sig_info, version); + if(version != 1 && version != 3) + throw Decoding_Error("CMS: Unknown version for SignedData"); + BER::get_subset(sig_info); // hash algos (do something with these?) + read_econtent(sig_info); + read_orig_info(sig_info, store); + + BER_Decoder signer_infos = BER::get_subset(sig_info); + while(signer_infos.more_items()) + { + AlgorithmIdentifier sig_algo, hash_algo; + SecureVector<byte> signature, digest; + u32bit version; + + BER_Decoder signer_info = BER::get_subsequence(signer_infos); + BER::decode(signer_info, version); + if(version != 1 && version != 3) + throw Decoding_Error("CMS: Unknown version for SignerInfo"); + + std::vector<X509_Certificate> certs = get_cert(signer_info, store); + if(certs.size() == 0) { status = NO_KEY; continue; } + + BER::decode(signer_info, hash_algo); + bool bad_attr = false; + digest = decode_attributes(signer_info, next_type, bad_attr); + if(bad_attr) { status = BAD; continue; } + BER::decode(signer_info, sig_algo); + BER::decode(signer_info, signature, OCTET_STRING); + // unsigned attributes + signer_info.verify_end(); + + if(digest.has_items()) + { + std::string hash; + if(digest != hash_of(data, hash_algo, hash)) + { + status = BAD; + continue; + } + status = check_sig(signed_attr, sig_algo, signature, certs[0]); + } + else + status = check_sig(data, sig_algo, signature, certs[0]); + + if(status == BAD) + continue; + + // fix this (gets only last signer, for one thing) + // maybe some way for the user to get all certs that signed the + // message? that would be useful + info = "CN=" + cert.subject_info("CommonName") + + ",O=" + cert.subject_info("Organization") + + ",OU=" + cert.subject_info("Organizational Unit"); + } +#endif + } + else if(type == OIDS::lookup("CMS.EnvelopedData")) + { + throw Exception("FIXME: not implemented"); + } + else if(type == OIDS::lookup("CMS.AuthenticatedData")) + { + throw Exception("FIXME: not implemented"); + } + else + throw Decoding_Error("CMS: Unknown content ID " + type.as_string()); + } + catch(std::exception) + { + status = FAILURE; + } + } + +} diff --git a/misc/cms/cms_dec.cpp b/misc/cms/cms_dec.cpp new file mode 100644 index 000000000..34ca82c19 --- /dev/null +++ b/misc/cms/cms_dec.cpp @@ -0,0 +1,114 @@ +/************************************************* +* CMS Decoding Source File * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#include <botan/cms_dec.h> +#include <botan/ber_dec.h> +#include <botan/oids.h> +#include <botan/pem.h> + +namespace Botan { + +/************************************************* +* CMS_Decoder Constructor * +*************************************************/ +CMS_Decoder::CMS_Decoder(DataSource& in, const X509_Store& x509store, + User_Interface& ui_ref, PKCS8_PrivateKey* key) : + ui(ui_ref), store(x509store) + { + status = GOOD; + + add_key(key); + + if(BER::maybe_BER(in) && !PEM_Code::matches(in)) + initial_read(in); + else + { + DataSource_Memory ber(PEM_Code::decode_check_label(in, "PKCS7")); + initial_read(ber); + } + } + +/************************************************* +* Read the outermost ContentInfo * +*************************************************/ +void CMS_Decoder::initial_read(DataSource& in) + { + BER_Decoder decoder(in); + BER_Decoder content_info = BER::get_subsequence(decoder); + BER::decode(content_info, next_type); + BER_Decoder content_type = BER::get_subsequence(content_info, ASN1_Tag(0)); + data = content_type.get_remaining(); + + decode_layer(); + } + +/************************************************* +* Add another private key to use * +*************************************************/ +void CMS_Decoder::add_key(PKCS8_PrivateKey* key) + { + if(!key) + return; + + for(u32bit j = 0; j != keys.size(); j++) + if(keys[j]->key_id() == key->key_id()) + return; + + keys.push_back(key); + } + +/************************************************* +* Return the status information * +*************************************************/ +CMS_Decoder::Status CMS_Decoder::layer_status() const + { + return status; + } + +/************************************************* +* Return the final data content * +*************************************************/ +std::string CMS_Decoder::get_data() const + { + if(layer_type() != DATA) + throw Invalid_State("CMS: Cannot retrieve data from non-DATA layer"); + return std::string((const char*)data.ptr(), data.size()); + } + +/************************************************* +* Return the content type of this layer * +*************************************************/ +CMS_Decoder::Content_Type CMS_Decoder::layer_type() const + { + if(type == OIDS::lookup("CMS.DataContent")) return DATA; + if(type == OIDS::lookup("CMS.EnvelopedData")) return ENVELOPED; + if(type == OIDS::lookup("CMS.CompressedData")) return COMPRESSED; + if(type == OIDS::lookup("CMS.SignedData")) return SIGNED; + if(type == OIDS::lookup("CMS.AuthenticatedData")) return AUTHENTICATED; + if(type == OIDS::lookup("CMS.DigestedData")) return DIGESTED; + return UNKNOWN; + } + +/************************************************* +* Return some information about this layer * +*************************************************/ +std::string CMS_Decoder::layer_info() const + { + return info; + } + +/************************************************* +* Return some information about this layer * +*************************************************/ +void CMS_Decoder::read_econtent(BER_Decoder& decoder) + { + BER_Decoder econtent_info = BER::get_subsequence(decoder); + BER::decode(econtent_info, next_type); + + BER_Decoder econtent = BER::get_subsequence(econtent_info, ASN1_Tag(0)); + BER::decode(econtent, data, OCTET_STRING); + } + +} diff --git a/misc/cms/cms_dec.h b/misc/cms/cms_dec.h new file mode 100644 index 000000000..4aac92e58 --- /dev/null +++ b/misc/cms/cms_dec.h @@ -0,0 +1,63 @@ +/************************************************* +* CMS Decoding Header File * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CMS_DECODER_H__ +#define BOTAN_CMS_DECODER_H__ + +#include <botan/x509cert.h> +#include <botan/x509stor.h> +#include <botan/pkcs8.h> +#include <botan/ber_dec.h> +#include <botan/ui.h> + +namespace Botan { + +/************************************************* +* CMS Decoding Operation * +*************************************************/ +class CMS_Decoder + { + public: + enum Status { GOOD, BAD, NO_KEY, FAILURE }; + + enum Content_Type { DATA, UNKNOWN, COMPRESSED, ENVELOPED, SIGNED, + AUTHENTICATED, DIGESTED }; + + Status layer_status() const; + Content_Type layer_type() const; + std::string layer_info() const; + std::string layer_algo() const; + std::string get_data() const; + std::vector<X509_Certificate> get_certs() const; + std::vector<X509_CRL> get_crls() const; + + void next_layer() { decode_layer(); } + + void add_key(PKCS8_PrivateKey*); + + CMS_Decoder(DataSource&, const X509_Store&, User_Interface&, + PKCS8_PrivateKey* = 0); + private: + std::string get_passphrase(const std::string&); + void read_econtent(BER_Decoder&); + void initial_read(DataSource&); + void decode_layer(); + void decompress(BER_Decoder&); + + User_Interface& ui; + + X509_Store store; + std::vector<std::string> passphrases; + std::vector<PKCS8_PrivateKey*> keys; + + OID type, next_type; + SecureVector<byte> data; + Status status; + std::string info; + }; + +} + +#endif diff --git a/misc/cms/cms_ealg.cpp b/misc/cms/cms_ealg.cpp new file mode 100644 index 000000000..e576f8c68 --- /dev/null +++ b/misc/cms/cms_ealg.cpp @@ -0,0 +1,369 @@ +/************************************************* +* CMS Encoding Operations Source File * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#include <botan/cms_enc.h> +#include <botan/der_enc.h> +#include <botan/oids.h> +#include <botan/lookup.h> +#include <botan/look_pk.h> +#include <botan/pipe.h> +#include <botan/conf.h> + +namespace Botan { + +namespace { + +/************************************************* +* Choose an algorithm * +*************************************************/ +std::string choose_algo(const std::string& user_algo, + const std::string& default_algo) + { + if(user_algo == "") + return deref_alias(default_algo); + return deref_alias(user_algo); + } + +/************************************************* +* Encode a SignerIdentifier/RecipientIdentifier * +*************************************************/ +void encode_si(DER_Encoder& encoder, const X509_Certificate& cert, + bool use_skid_encoding = false) + { + if(cert.has_SKID() && use_skid_encoding) + DER::encode(encoder, cert.subject_key_id(), OCTET_STRING, ASN1_Tag(0)); + else + { + encoder.start_sequence(); + DER::encode(encoder, cert.issuer_dn()); + DER::encode(encoder, cert.serial_number_bn()); + encoder.end_sequence(); + } + } + +/************************************************* +* Compute the hash of some content * +*************************************************/ +SecureVector<byte> hash_of(const SecureVector<byte>& content, + const std::string& hash) + { + std::auto_ptr<HashFunction> hash_fn(get_hash(hash)); + return hash_fn->process(content); + } + +/************************************************* +* Encode Attributes containing info on content * +*************************************************/ +SecureVector<byte> encode_attr(const SecureVector<byte>& data, + const std::string& type, + const std::string& hash) + { + SecureVector<byte> digest = hash_of(data, hash); + + DER_Encoder encoder; + DER::encode(encoder, OIDS::lookup(type)); + Attribute content_type("PKCS9.ContentType", encoder.get_contents()); + + DER::encode(encoder, digest, OCTET_STRING); + Attribute message_digest("PKCS9.MessageDigest", encoder.get_contents()); + + encoder.start_set(); + DER::encode(encoder, content_type); + DER::encode(encoder, message_digest); + encoder.end_set(); + + return encoder.get_contents(); + } + +} + +/************************************************* +* Encrypt a message * +*************************************************/ +void CMS_Encoder::encrypt(const X509_Certificate& to, + const std::string user_cipher) + { + const std::string cipher = choose_algo(user_cipher, "TripleDES"); + + std::auto_ptr<X509_PublicKey> key(to.subject_public_key()); + const std::string algo = key->algo_name(); + + Key_Constraints constraints = to.get_constraints(); + + if(algo == "RSA") + { + if(constraints != NO_CONSTRAINTS && !(constraints & KEY_ENCIPHERMENT)) + throw Invalid_Argument("CMS: Constraints not set for encryption"); + + PK_Encrypting_Key* enc_key = dynamic_cast<PK_Encrypting_Key*>(key.get()); + if(enc_key == 0) + throw Internal_Error("CMS_Encoder::encrypt: " + algo + + " can't encrypt"); + + encrypt_ktri(to, enc_key, cipher); + } + else if(algo == "DH") + { + if(constraints != NO_CONSTRAINTS && !(constraints & KEY_AGREEMENT)) + throw Invalid_Argument("CMS: Constraints not set for key agreement"); + + encrypt_kari(to, key.get(), cipher); + } + else + throw Invalid_Argument("Unknown CMS PK encryption algorithm " + algo); + } + +/************************************************* +* Encrypt a message with a key transport algo * +*************************************************/ +void CMS_Encoder::encrypt_ktri(const X509_Certificate& to, + PK_Encrypting_Key* pub_key, + const std::string& cipher) + { + const std::string padding = "EME-PKCS1-v1_5"; + const std::string pk_algo = pub_key->algo_name(); + std::auto_ptr<PK_Encryptor> enc(get_pk_encryptor(*pub_key, padding)); + + SymmetricKey cek = setup_key(cipher); + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, 0); + encoder.start_set(); + encoder.start_sequence(); + DER::encode(encoder, 0); + encode_si(encoder, to); + DER::encode(encoder, AlgorithmIdentifier(pk_algo + "/" + padding)); + DER::encode(encoder, enc->encrypt(cek.copy()), OCTET_STRING); + encoder.end_sequence(); + encoder.end_set(); + encoder.add_raw_octets(do_encrypt(cek, cipher)); + encoder.end_sequence(); + + add_layer("CMS.EnvelopedData", encoder); + } + +/************************************************* +* Encrypt a message with a key agreement algo * +*************************************************/ +void CMS_Encoder::encrypt_kari(const X509_Certificate&, + X509_PublicKey*, + const std::string&) + { + throw Exception("FIXME: unimplemented"); +#if 0 + SymmetricKey cek = setup_key(cipher); + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, 2); + encoder.start_set(); + encoder.start_sequence(ASN1_Tag(1)); + DER::encode(encoder, 3); + encode_si(encoder, to); + DER::encode(encoder, AlgorithmIdentifier(pk_algo + "/" + padding)); + DER::encode(encoder, encrypted_cek, OCTET_STRING); + encoder.end_sequence(ASN1_Tag(1)); + encoder.end_set(); + encoder.add_raw_octets(do_encrypt(cek, cipher)); + encoder.end_sequence(); + + add_layer("CMS.EnvelopedData", encoder); +#endif + } + +/************************************************* +* Encrypt a message with a shared key * +*************************************************/ +void CMS_Encoder::encrypt(const SymmetricKey& kek, + const std::string& user_cipher) + { + throw Exception("FIXME: untested"); + + const std::string cipher = choose_algo(user_cipher, "TripleDES"); + SymmetricKey cek = setup_key(cipher); + + SecureVector<byte> kek_id; // FIXME: ? + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, 2); + encoder.start_sequence(ASN1_Tag(2)); + DER::encode(encoder, 4); + encoder.start_sequence(); + DER::encode(encoder, kek_id, OCTET_STRING); + encoder.end_sequence(); + DER::encode(encoder, AlgorithmIdentifier("KeyWrap." + cipher, true)); + DER::encode(encoder, wrap_key(cipher, cek, kek), OCTET_STRING); + encoder.end_sequence(ASN1_Tag(2)); + encoder.add_raw_octets(do_encrypt(cek, cipher)); + encoder.end_sequence(); + + add_layer("CMS.EnvelopedData", encoder); + } + +/************************************************* +* Encrypt a message with a passphrase * +*************************************************/ +void CMS_Encoder::encrypt(const std::string&, + const std::string& user_cipher) + { + const std::string cipher = choose_algo(user_cipher, "TripleDES"); + throw Exception("FIXME: unimplemented"); + /* + SymmetricKey cek = setup_key(key); + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, 0); + encoder.add_raw_octets(do_encrypt(cek, cipher)); + encoder.end_sequence(); + + add_layer("CMS.EnvelopedData", encoder); + */ + } + +/************************************************* +* Encrypt the content with the chosen key/cipher * +*************************************************/ +SecureVector<byte> CMS_Encoder::do_encrypt(const SymmetricKey& key, + const std::string& cipher) + { + if(!have_block_cipher(cipher)) + throw Invalid_Argument("CMS: Can't encrypt with non-existent cipher " + + cipher); + if(!OIDS::have_oid(cipher + "/CBC")) + throw Encoding_Error("CMS: No OID assigned for " + cipher + "/CBC"); + + InitializationVector iv(block_size_of(cipher)); + + AlgorithmIdentifier content_cipher; + content_cipher.oid = OIDS::lookup(cipher + "/CBC"); + content_cipher.parameters = encode_params(cipher, key, iv); + + Pipe pipe(get_cipher(cipher + "/CBC/PKCS7", key, iv, ENCRYPTION)); + pipe.process_msg(data); + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, OIDS::lookup(type)); + DER::encode(encoder, content_cipher); + DER::encode(encoder, pipe.read_all(), OCTET_STRING, ASN1_Tag(0)); + encoder.end_sequence(); + + return encoder.get_contents(); + } + +/************************************************* +* Sign a message * +*************************************************/ +void CMS_Encoder::sign(X509_Store& store, const PKCS8_PrivateKey& key) + { + std::vector<X509_Certificate> matching = + X509_Store_Search::by_keyid(store, key.key_id()); + if(matching.size() == 0) + throw Encoding_Error("CMS::sign: Cannot find cert matching given key"); + + const X509_Certificate& cert = matching[0]; + + std::vector<X509_Certificate> chain = store.get_cert_chain(cert); + + std::string padding, hash; + Signature_Format format; + Config::choose_sig_format(key.algo_name(), padding, hash, format); + const std::string sig_algo = key.algo_name() + "/" + padding; + + SecureVector<byte> signed_attr = encode_attr(data, type, hash); + const PK_Signing_Key& sig_key = dynamic_cast<const PK_Signing_Key&>(key); + std::auto_ptr<PK_Signer> signer(get_pk_signer(sig_key, padding, format)); + signer->update(signed_attr); + SecureVector<byte> signature = signer->signature(); + signed_attr[0] = 0xA0; + + const u32bit SI_VERSION = cert.has_SKID() ? 3 : 1; + const u32bit CMS_VERSION = (type != "CMS.DataContent") ? 3 : SI_VERSION; + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, CMS_VERSION); + encoder.start_set(); + DER::encode(encoder, AlgorithmIdentifier(hash, true)); + encoder.end_set(); + encoder.add_raw_octets(make_econtent(data, type)); + + encoder.start_set(ASN1_Tag(0)); + for(u32bit j = 0; j != chain.size(); j++) + encoder.add_raw_octets(chain[j].BER_encode()); + encoder.add_raw_octets(cert.BER_encode()); + encoder.end_set(ASN1_Tag(0)); + + encoder.start_set(); + encoder.start_sequence(); + DER::encode(encoder, SI_VERSION); + encode_si(encoder, cert, ((SI_VERSION == 3) ? true : false)); + DER::encode(encoder, AlgorithmIdentifier(hash, true)); + encoder.add_raw_octets(signed_attr); + DER::encode(encoder, AlgorithmIdentifier(sig_algo, true)); + DER::encode(encoder, signature, OCTET_STRING); + encoder.end_sequence(); + encoder.end_set(); + encoder.end_sequence(); + + add_layer("CMS.SignedData", encoder); + } + +/************************************************* +* Digest a message * +*************************************************/ +void CMS_Encoder::digest(const std::string& user_hash) + { + const std::string hash = choose_algo(user_hash, "SHA-1"); + if(!OIDS::have_oid(hash)) + throw Encoding_Error("CMS: No OID assigned for " + hash); + + const u32bit VERSION = (type != "CMS.DataContent") ? 2 : 0; + + DER_Encoder encoder; + encoder.start_sequence(); + DER::encode(encoder, VERSION); + DER::encode(encoder, AlgorithmIdentifier(hash, true)); + encoder.add_raw_octets(make_econtent(data, type)); + DER::encode(encoder, hash_of(data, hash), OCTET_STRING); + encoder.end_sequence(); + + add_layer("CMS.DigestedData", encoder); + } + +/************************************************* +* MAC a message with an encrypted key * +*************************************************/ +void CMS_Encoder::authenticate(const X509_Certificate&, + const std::string& mac_algo) + { + const std::string mac = choose_algo(mac_algo, "HMAC(SHA-1)"); + throw Exception("FIXME: unimplemented"); + } + +/************************************************* +* MAC a message with a shared key * +*************************************************/ +void CMS_Encoder::authenticate(const SymmetricKey&, + const std::string& mac_algo) + { + const std::string mac = choose_algo(mac_algo, "HMAC(SHA-1)"); + throw Exception("FIXME: unimplemented"); + } + +/************************************************* +* MAC a message with a passphrase * +*************************************************/ +void CMS_Encoder::authenticate(const std::string&, + const std::string& mac_algo) + { + const std::string mac = choose_algo(mac_algo, "HMAC(SHA-1)"); + throw Exception("FIXME: unimplemented"); + } + +} diff --git a/misc/cms/cms_enc.cpp b/misc/cms/cms_enc.cpp new file mode 100644 index 000000000..58b3eadf6 --- /dev/null +++ b/misc/cms/cms_enc.cpp @@ -0,0 +1,87 @@ +/************************************************* +* CMS Encoding Base Source File * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#include <botan/cms_enc.h> +#include <botan/der_enc.h> +#include <botan/oids.h> +#include <botan/pem.h> + +namespace Botan { + +/************************************************* +* Setup the intitial layer of CMS data * +*************************************************/ +void CMS_Encoder::set_data(const byte buf[], u32bit length) + { + if(data.has_items()) + throw Invalid_State("Cannot call CMS_Encoder::set_data here"); + + data.set(buf, length); + type = "CMS.DataContent"; + } + +/************************************************* +* Setup the intitial layer of CMS data * +*************************************************/ +void CMS_Encoder::set_data(const std::string& str) + { + set_data((const byte*)str.c_str(), str.length()); + } + +/************************************************* +* Finalize and return the CMS encoded data * +*************************************************/ +SecureVector<byte> CMS_Encoder::get_contents() + { + DER_Encoder encoder; + + encoder.start_sequence(); + DER::encode(encoder, OIDS::lookup(type)); + encoder.start_explicit(ASN1_Tag(0)); + encoder.add_raw_octets(data); + encoder.end_explicit(ASN1_Tag(0)); + encoder.end_sequence(); + + data.clear(); + + return encoder.get_contents(); + } + +/************************************************* +* Add a new layer of encapsulation * +*************************************************/ +void CMS_Encoder::add_layer(const std::string& oid, DER_Encoder& new_layer) + { + data = new_layer.get_contents(); + type = oid; + } + +/************************************************* +* Return the PEM-encoded data * +*************************************************/ +std::string CMS_Encoder::PEM_contents() + { + return PEM_Code::encode(get_contents(), "PKCS7"); + } + +/************************************************* +* Make an EncapsulatedContentInfo * +*************************************************/ +SecureVector<byte> CMS_Encoder::make_econtent(const SecureVector<byte>& data, + const std::string& type) + { + DER_Encoder encoder; + + encoder.start_sequence(); + DER::encode(encoder, OIDS::lookup(type)); + encoder.start_explicit(ASN1_Tag(0)); + DER::encode(encoder, data, OCTET_STRING); + encoder.end_explicit(ASN1_Tag(0)); + encoder.end_sequence(); + + return encoder.get_contents(); + } + +} diff --git a/misc/cms/cms_enc.h b/misc/cms/cms_enc.h new file mode 100644 index 000000000..ac0634985 --- /dev/null +++ b/misc/cms/cms_enc.h @@ -0,0 +1,70 @@ +/************************************************* +* CMS Encoding Header File * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#ifndef BOTAN_CMS_ENCODER_H__ +#define BOTAN_CMS_ENCODER_H__ + +#include <botan/x509cert.h> +#include <botan/x509stor.h> +#include <botan/pkcs8.h> + +namespace Botan { + +/************************************************* +* CMS Encoding Operation * +*************************************************/ +class CMS_Encoder + { + public: + void encrypt(const X509_Certificate&, const std::string = ""); + void encrypt(const std::string&, const std::string& = ""); + void encrypt(const SymmetricKey&, const std::string& = ""); + + void authenticate(const X509_Certificate&, const std::string& = ""); + void authenticate(const std::string&, const std::string& = ""); + void authenticate(const SymmetricKey&, const std::string& = ""); + + void sign(X509_Store&, const PKCS8_PrivateKey&); + void digest(const std::string& = ""); + + void compress(const std::string&); + static bool can_compress_with(const std::string&); + + SecureVector<byte> get_contents(); + std::string PEM_contents(); + + void set_data(const std::string&); + void set_data(const byte[], u32bit); + + CMS_Encoder(const std::string& str) { set_data(str); } + CMS_Encoder(const byte buf[], u32bit length) { set_data(buf, length); } + private: + void add_layer(const std::string&, DER_Encoder&); + + void encrypt_ktri(const X509_Certificate&, PK_Encrypting_Key*, + const std::string&); + void encrypt_kari(const X509_Certificate&, X509_PublicKey*, + const std::string&); + + SecureVector<byte> do_encrypt(const SymmetricKey&, const std::string&); + + static SecureVector<byte> make_econtent(const SecureVector<byte>&, + const std::string&); + + static SymmetricKey setup_key(const std::string&); + static SecureVector<byte> wrap_key(const std::string&, + const SymmetricKey&, + const SymmetricKey&); + static SecureVector<byte> encode_params(const std::string&, + const SymmetricKey&, + const InitializationVector&); + + SecureVector<byte> data; + std::string type; + }; + +} + +#endif diff --git a/misc/cms/readme.txt b/misc/cms/readme.txt new file mode 100644 index 000000000..b4a0afad0 --- /dev/null +++ b/misc/cms/readme.txt @@ -0,0 +1,24 @@ +Botan CMS alpha1 +December 12, 2003 + +To use this, download a recent version of Botan (1.2.8 or 1.3.7 are best), and +move the source files to src/, the headers to include/ and then run +configure/make as normal. You will then have a CMS encoder/decoder. There are a +couple of testing apps in testing/ which should show the general idea. Lots of +it is unimplemented (which it will tell you by throwing exceptions), but basic +RSA encryption/signatures and a few other things work OK. The encoder is much +more complete than the decoder. + +The encoder works by initializing it with some bits, then calling some number +of operations on it (compress(), digest(), encrypt(), etc) which successfully +'envelope' the data. The decoder works exactly the same, except backwards. (Of +course!) + +This was supposed to have been finished by now, but it's kind of stalled. I +want CMS support, I just don't really want to code it. So I've been occupying +myself with various distractions. I'll probably finish it *someday*. + +If someone out there really wants this soon, and is willing to pay some nominal +consulting fee (we're talking cheap), let me know and we can talk about +it. I think I need some external motivation of some sort to force me to tell +with the mess that is CMS. diff --git a/misc/cms/tests/cacert.pem b/misc/cms/tests/cacert.pem new file mode 100644 index 000000000..70263abe0 --- /dev/null +++ b/misc/cms/tests/cacert.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICYjCCAcugAwIBAgIRAMccNerZcWvudgzuyzcOVjgwDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCUFIxEjAQBgNVBAoTCVByaW9uQ29ycDEaMBgGA1UEAxMRUHJp +b25Db3JwIFJvb3QgQ0EwHhcNMDMxMTA5MDEyNjA0WhcNMDQxMTA4MDEyNjM0WjA9 +MQswCQYDVQQGEwJQUjESMBAGA1UEChMJUHJpb25Db3JwMRowGAYDVQQDExFQcmlv +bkNvcnAgUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtXP7pUMt +iL/Vbz9keSw7V/UClsVoCnybHNoHt1hU8WXGInUeZdBmZdhga/N/ugH0LvvFyERT +63oJz92vbv7sSYjueaPFVP2g+CIJfZPsVsy5G91YyYUFxrevCkVB21VxcRqlflo8 +DokB3t58rJ4+OKkR9aqs/QMT8MS7z3J/FzkCAwEAAaNiMGAwHQYDVR0OBBYEFHL3 +F37cN9LKEouhUYfWMLDzsk92MBIGA1UdEwEB/wQIMAYBAf8CAQgwGwYDVR0RBBQw +EoEQY2FAcHJpb25jb3JwLmNvbTAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEF +BQADgYEAZ+NKT1Y6ciyM2IInE7IXw+npYhzA22HsTk+vxJVOpBt+9wAucqpKxiVs +SbYtwabP/4DoKnurHRojoKTdkGGDkco+9Vmlt/9eiTa8WqIeiWnnPV4k1VeWdGA0 +nei/Ds0KG5crGtqmX8DUjz9r5E43pnEMR2T7LuDg/Ko/WZissh0= +-----END CERTIFICATE----- diff --git a/misc/cms/tests/cms_dec.cpp b/misc/cms/tests/cms_dec.cpp new file mode 100644 index 000000000..593cf2e09 --- /dev/null +++ b/misc/cms/tests/cms_dec.cpp @@ -0,0 +1,111 @@ +#include <botan/cms_dec.h> +using namespace Botan; + +#include <iostream> + +int main(int argc, char* argv[]) + { + if(argc != 2) + { + printf("Usage: %s <filename>\n", argv[0]); + return 1; + } + + LibraryInitializer init; + + try { + X509_Certificate mycert("mycert.pem"); + PKCS8_PrivateKey* mykey = PKCS8::load_key("mykey.pem", "cut"); + + X509_Certificate yourcert("yourcert.pem"); + X509_Certificate cacert("cacert.pem"); + X509_Certificate int_ca("int_ca.pem"); + + X509_Store store; + store.add_cert(mycert); + store.add_cert(yourcert); + store.add_cert(cacert, true); + store.add_cert(int_ca); + + DataSource_Stream message(argv[1]); + + User_Interface ui; + + CMS_Decoder decoder(message, store, ui, mykey); + + while(decoder.layer_type() != CMS_Decoder::DATA) + { + CMS_Decoder::Status status = decoder.layer_status(); + CMS_Decoder::Content_Type content = decoder.layer_type(); + + if(status == CMS_Decoder::FAILURE) + { + std::cout << "Failure reading CMS data" << std::endl; + break; + } + + if(content == CMS_Decoder::DIGESTED) + { + std::cout << "Digested data, hash = " << decoder.layer_info() + << std::endl; + std::cout << "Hash is " + << ((status == CMS_Decoder::GOOD) ? "good" : "bad") + << std::endl; + } + + if(content == CMS_Decoder::SIGNED) + { + // how to handle multiple signers? they can all exist within a + // single level... + + std::cout << "Signed by " << decoder.layer_info() << std::endl; + //std::cout << "Sign time: " << decoder.xxx() << std::endl; + std::cout << "Signature is "; + if(status == CMS_Decoder::GOOD) + std::cout << "valid"; + else if(status == CMS_Decoder::BAD) + std::cout << "bad"; + else if(status == CMS_Decoder::NO_KEY) + std::cout << "(cannot check, no known cert)"; + std::cout << std::endl; + } + if(content == CMS_Decoder::ENVELOPED || + content == CMS_Decoder::COMPRESSED || + content == CMS_Decoder::AUTHENTICATED) + { + if(content == CMS_Decoder::ENVELOPED) + std::cout << "Enveloped"; + if(content == CMS_Decoder::COMPRESSED) + std::cout << "Compressed"; + if(content == CMS_Decoder::AUTHENTICATED) + std::cout << "MACed"; + + std::cout << ", algo = " << decoder.layer_info() << std::endl; + + if(content == CMS_Decoder::AUTHENTICATED) + { + std::cout << "MAC status is "; + if(status == CMS_Decoder::GOOD) + std::cout << "valid"; + else if(status == CMS_Decoder::BAD) + std::cout << "bad"; + else if(status == CMS_Decoder::NO_KEY) + std::cout << "(cannot check, no key)"; + std::cout << std::endl; + } + } + decoder.next_layer(); + } + + if(decoder.layer_type() == CMS_Decoder::DATA) + std::cout << "Message is \"" << decoder.get_data() + << '"' << std::endl; + else + std::cout << "No data anywhere?" << std::endl; + } + catch(std::exception& e) + { + std::cerr << e.what() << std::endl; + } + return 0; + } diff --git a/misc/cms/tests/cms_enc.cpp b/misc/cms/tests/cms_enc.cpp new file mode 100644 index 000000000..0319925d8 --- /dev/null +++ b/misc/cms/tests/cms_enc.cpp @@ -0,0 +1,46 @@ +#include <botan/cms_enc.h> +using namespace Botan; + +#include <iostream> +#include <fstream> + +int main() + { + LibraryInitializer init; + + try { + PKCS8_PrivateKey* mykey = PKCS8::load_key("mykey.pem", "cut"); + + X509_Certificate mycert("mycert.pem"); + X509_Certificate mycert2("mycert2.pem"); + X509_Certificate yourcert("yourcert.pem"); + X509_Certificate cacert("cacert.pem"); + X509_Certificate int_ca("int_ca.pem"); + + X509_Store store; + store.add_cert(mycert); + store.add_cert(mycert2); + store.add_cert(yourcert); + store.add_cert(int_ca); + store.add_cert(cacert, true); + + const std::string msg = "prioncorp: we don't toy\n"; + + CMS_Encoder encoder(msg); + + encoder.compress("Zlib"); + encoder.digest(); + encoder.encrypt(mycert); + encoder.sign(store, *mykey); + + SecureVector<byte> raw = encoder.get_contents(); + std::ofstream out("out.der"); + + out.write((const char*)raw.ptr(), raw.size()); + } + catch(std::exception& e) + { + std::cerr << e.what() << std::endl; + } + return 0; + } diff --git a/misc/cms/tests/int_ca.pem b/misc/cms/tests/int_ca.pem new file mode 100644 index 000000000..85e35ab88 --- /dev/null +++ b/misc/cms/tests/int_ca.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC3zCCAkigAwIBAgIRAIfaYqkyhxP/BUSIiqx9/bUwDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCUFIxEjAQBgNVBAoTCVByaW9uQ29ycDEaMBgGA1UEAxMRUHJp +b25Db3JwIFJvb3QgQ0EwHhcNMDMxMTA5MDEzMjA1WhcNMDQxMTA4MDEzMjA1WjBu +MQswCQYDVQQGEwJVUzELMAkGA1UECBMCTUQxEjAQBgNVBAcTCUJhbHRpbW9yZTES +MBAGA1UEChMJUHJpb25Db3JwMRAwDgYDVQQLEwdUZXN0aW5nMRgwFgYDVQQDEw9Q +cmlvbiBQZXJzb25uZWwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL2cw+jh +K17j+SBFJqC2oaiPW70T1chtJ1EOtG+SovZXgmLk29fVJCWq1YuihGAOXJUBVGgS +1/IO2WhE3DaU2ekMiiXCQd1cVBLuhrg2aGzOGUifrvvgaLYUHRvctnuYBh/hm04+ +GFpWMeIaly9ZH+yImd6Td7n1yrzsq7Evl/+lAgMBAAGjga0wgaowHQYDVR0OBBYE +FEbeVBJJPVESjB0ZEYaorZU/WxVlMB8GA1UdIwQYMBaAFHL3F37cN9LKEouhUYfW +MLDzsk92MBIGA1UdEwEB/wQIMAYBAf8CAQgwGwYDVR0RBBQwEoEQcHBAcHJpb25j +b3JwLmNvbTAOBgNVHQ8BAf8EBAMCAQYwJwYDVR0lBCAwHgYIKwYBBQUHAwIGCCsG +AQUFBwMHBggrBgEFBQcDBDANBgkqhkiG9w0BAQUFAAOBgQAOBYopIXBr8rq95GW3 +l5I/8IKuUq0/jBzW9766uv1GJUS37CcsQ0isdDrBASZfae4nqWUTIRbEVZ6s0yNb +fauzzoPv13EwnxZECUKADJpLaYgH43v6oil47ljFuuhANQMMFAQ8kTwhUkM4F0eQ +VGBoTBmoIV2Vppf/MRIpQIq0pA== +-----END CERTIFICATE----- diff --git a/misc/cms/tests/mycert.pem b/misc/cms/tests/mycert.pem new file mode 100644 index 000000000..05082b3bf --- /dev/null +++ b/misc/cms/tests/mycert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDAzCCAmygAwIBAgIRAOVlsPFarxiOCqAgatU2fpgwDQYJKoZIhvcNAQEFBQAw +bjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1EMRIwEAYDVQQHEwlCYWx0aW1vcmUx +EjAQBgNVBAoTCVByaW9uQ29ycDEQMA4GA1UECxMHVGVzdGluZzEYMBYGA1UEAxMP +UHJpb24gUGVyc29ubmVsMB4XDTAzMTEwOTAxMzMzN1oXDTA0MTEwODAxMzMzN1ow +ZDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1EMRIwEAYDVQQHEwlCYWx0aW1vcmUx +EjAQBgNVBAoTCVByaW9uQ29ycDEQMA4GA1UECxMHVGVzdGluZzEOMAwGA1UEAxMF +R1JPSUQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKf3JbJymfnnelEy4HrK +0wcwOCO6F6W1u98VV01RKEJtff/0m2QVVPRuHXtofZOWwwxZ9e4X2mB+Q1DQjkZM +Q9d/sPvNtIL47QVRNOc9EnfaoGbohlTT+dONj8eYWQ1PU5FtADAEXmXwTWsCk5eO +arpISIyda3bMycwx4hGkwcxHAgMBAAGjgaowgacwHQYDVR0OBBYEFFQgVRRLqxb8 +FJ+s7OQB++dmXdVmMB8GA1UdIwQYMBaAFEbeVBJJPVESjB0ZEYaorZU/WxVlMAwG +A1UdEwEB/wQCMAAwHgYDVR0RBBcwFYETZ3JvaWRAcHJpb25jb3JwLmNvbTAOBgNV +HQ8BAf8EBAMCBeAwJwYDVR0lBCAwHgYIKwYBBQUHAwIGCCsGAQUFBwMHBggrBgEF +BQcDBDANBgkqhkiG9w0BAQUFAAOBgQA2g/iN3cQUDqG5yEzoTtmvDlOkwRruYLOn +8/M7znnPk28l1QVtIy+mCgbFP5khNEHo3ogSjVI83FlRFDTx4mXV81hwK+xi/eLW +MeNfJdHxqRuMMbY9/a2To90jS0NRsCCI917QlT0iOVBpoe0i28Is7ofRZ0MKtZMY +cxcB6XWeug== +-----END CERTIFICATE----- diff --git a/misc/cms/tests/mycert2.pem b/misc/cms/tests/mycert2.pem new file mode 100644 index 000000000..d7efb31ea --- /dev/null +++ b/misc/cms/tests/mycert2.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEHTCCA4agAwIBAgIRANP/9If4mMQ1Y+EIPrzxWg0wDQYJKoZIhvcNAQEFBQAw +bjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1EMRIwEAYDVQQHEwlCYWx0aW1vcmUx +EjAQBgNVBAoTCVByaW9uQ29ycDEQMA4GA1UECxMHVGVzdGluZzEYMBYGA1UEAxMP +UHJpb24gUGVyc29ubmVsMB4XDTAzMTExMjA0MzUxNFoXDTA0MTExMTA0MzUxNFow +ZDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1EMRIwEAYDVQQHEwlCYWx0aW1vcmUx +EjAQBgNVBAoTCVByaW9uQ29ycDEQMA4GA1UECxMHVGVzdGluZzEOMAwGA1UEAxMF +R1JPSUQwggG3MIIBKwYHKoZIzjgEATCCAR4CgYEA/X9TgR11EilS30qcLuzk5/YR +t1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZ +UKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu +K2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgEaWA1EuMCeM +05R1ldsi7smCamMirclzRPQddAwyVyTI+e+6p9TYA/+MYJ3NEA68W9/PrXxqQl+u +p4bqIFDr6YNR6h/aH98k1pR6prmqI3ZpU4AvTX1KjsugbRl2iiSR/7FtDvnEOpm1 +9xZy/28KJLRE0HNtBNOKGhMi2vbN2IydA4GFAAKBgQDolXHX/FpKLzYJYlYXxS29 ++Fvug5lma45gnX68o5v+v5lrZgXJ3o6AP1WL9Y5rWrCwCNFMJ/60s9XxBPBXyD4H +bQp0nDFrtkigMrC/Ue/btjzLThKrGhnWNh0EYw/BURsbbaOnxzi8hpIc1n8qXDuK +hlkxUUvovfHj2E4G7IzKdaOBqzCBqDAdBgNVHQ4EFgQU84gmHCKCv04yWRXHbQPq +SX0fzBQwHwYDVR0jBBgwFoAURt5UEkk9URKMHRkRhqitlT9bFWUwDAYDVR0TAQH/ +BAIwADAfBgNVHREEGDAWgRRncm9pZEBicnV0YWx1bml0LmNvbTAOBgNVHQ8BAf8E +BAMCBsAwJwYDVR0lBCAwHgYIKwYBBQUHAwIGCCsGAQUFBwMHBggrBgEFBQcDBDAN +BgkqhkiG9w0BAQUFAAOBgQC4YptXYHJIs/mTaTnTKNSPYSEN8sYfuS5r6pRPbxsM +8uusP2vPgzAVCnQpg27/m9SdcAyZb+yiVCRZ5Kk5+CIKWfWNJDmcBxFJlL+UL7x0 +Qor1+B/IlmPNOZHlXDkpEFA6A9UC8aGYwA9DJmcdMdXxaQy2b1d9en0WyxBRQMnY +6A== +-----END CERTIFICATE----- diff --git a/misc/cms/tests/mykey.pem b/misc/cms/tests/mykey.pem new file mode 100644 index 000000000..46e94e140 --- /dev/null +++ b/misc/cms/tests/mykey.pem @@ -0,0 +1,17 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICyTBDBgkqhkiG9w0BBQ0wNjAeBgkqhkiG9w0BBQwwEQQI34hFoRijoOICAggA +AgEYMBQGCCqGSIb3DQMHBAgTmcMqYk8EZQSCAoAPeiGKaCNgcbfoTV/Pxc9TducM +cAMdHvETAVQVR9k7dGqmbtkaMH+0tVwJwtDhn9/bEvf6xC1zwlyIQ7b4J94/IMf5 +17IIVGMn1P2f46ASvw+Y9BPD9JPUh96Ohkya5SHX+UiRWR0EGQhfzKFcO8YC2Sl6 ++7itEw9boojYDFRt2W3hEEGURZGZiMH7dOlRCLzF6F+qOzNs79RwBWTaWK5TCu0N +Vdo8ulqLEo63Wxc6dN5utr6RSBOFP1wKLjQd+lBmW7T/PuwKwUch6UzTdNwVuSKP +3JJXdZykCxrDRIKevwyotaVU+7XWV+WrLgcli95N3eKpeWgVr+qT/HPjTkCFPi0p +1iLLht56kilRRMsizV0LlQjdzqt5Sketp8kAqsEV/AjwrUfDP0QF/iCaVZ0Z7i3O +71RrlW2a3LDUUTLRS6/4e28ATuSIxb5fTJktmK102Q8GdH0dNIfrkUBK6xgthzEN +FGPrYGdbxSHxR6k8Q7hMKmYEqmUSo27nOfKbOJlbwS6xGtpAH8dC/bb1JjnyYGfR +0kqVHGkTQqsMqBLKjNvzYXvEX1BokqXD+KafunWmHhMeQzyOYRgagPsKalMMFz53 +EP7EgMCjhkC222wEbyAPWCjuKZ2OOZnqHr/3MSFOVUQIELFNcPpJcf7+C/hGQjV9 +OWaSWSFa6eQGvNJsBXbQQCBSY8FvCliQcn2e3PG98RPC6FHbSgjsW10Z8WNiWKOG +F5MM7Pov4GIEcT/6b8DhRkNwB9PWlcnVR2jUgEX5UcB2tgljHshR3gKC9LnLQn+B +xB+uTrsnd4G9dCkhg2NmgZ0ghJ2katupqbwpADd13kXGXCVLjfuksYxTX1S1 +-----END ENCRYPTED PRIVATE KEY----- diff --git a/misc/cms/tests/mykey2.pem b/misc/cms/tests/mykey2.pem new file mode 100644 index 000000000..69cc76111 --- /dev/null +++ b/misc/cms/tests/mykey2.pem @@ -0,0 +1,11 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBmTBDBgkqhkiG9w0BBQ0wNjAeBgkqhkiG9w0BBQwwEQQI3mP0zRQGjQgCAggA +AgEYMBQGCCqGSIb3DQMHBAiwp1QHcRxj0ASCAVCmM0QKIyYDS3iggiZjG300eV1N +MxFKSfre39BuMNZhd0hIA5T7F+Do84d1dwhK8wdxq5yLRq9pcHaLCYm0iPdtPzVO +OIunUD/3CudNHu6rdBE+rtfd8rLuzHnkgTJJY5wxIGaZdu7O7J8fuBPt5/gTF+an ++rO4U4ZJiFvCCfQzjQHyFUinVAxTE9OozguhcIj3TMnZQwSpXw8HYVVNO+WAN1n1 ++6moNYbKmd69hrKnmg3uxmV7hPBTeFssrdlny3G9yCb5bIPZ/URpv0sM/HLkH2Gl +3v0m50okhnkNIgUgQ45sg2/u6cyoMqxuP7te4jPWalWY0FFMt/Kx8O0eL9eZwcK3 +Vs0QYt6MzCRVRPsrdHFczOHT5Ygk3MW0ZP8uLNJjhDPVYCaJprIuk19wco0z8a7x +734n8uHqlpzOUE7LpGcmaIOeEe7fIr4ZnIfw7QU= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/misc/cms/tests/yourcert.pem b/misc/cms/tests/yourcert.pem new file mode 100644 index 000000000..bea147354 --- /dev/null +++ b/misc/cms/tests/yourcert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC1zCCAkCgAwIBAgIRAOe/xWvUYwSm0TOMqoPF2u0wDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCUFIxEjAQBgNVBAoTCVByaW9uQ29ycDEaMBgGA1UEAxMRUHJp +b25Db3JwIFJvb3QgQ0EwHhcNMDMxMTA5MDEyOTExWhcNMDQxMTA4MDEyOTExWjBn +MQswCQYDVQQGEwJSVTELMAkGA1UECBMCTUQxEjAQBgNVBAcTCUJhbHRpbW9yZTES +MBAGA1UEChMJUHJpb25Db3JwMRAwDgYDVQQLEwdUZXN0aW5nMREwDwYDVQQDEwgy +OTdCMDU4MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3Td7nAtgyM4nxiYX +wRMqyJ39XkHnR4YIMjK9nHr4adIbJcRD5xRRylIUweQiLjc3nTn5uDjXggRCbcV8 +l7aJP20S9Rm5Z5HOYH1UH2KqEmF1JIXj/0DCfl51InFOpKhlVUdXy3hB18Pp9y4X +wnvl3xblumNIlyUeFv6klA1vQQUCAwEAAaOBrDCBqTAdBgNVHQ4EFgQUP10rBSlh +YKuDOLTKlgXPzXGavcUwHwYDVR0jBBgwFoAUcvcXftw30soSi6FRh9YwsPOyT3Yw +DAYDVR0TAQH/BAIwADAgBgNVHREEGTAXgRUyOTdCMDU4M0BwcmlvbmNvcnAucnUw +DgYDVR0PAQH/BAQDAgXgMCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDBwYI +KwYBBQUHAwQwDQYJKoZIhvcNAQEFBQADgYEAlZJaF89dOIfocPHEvsKuU58LwjPC +FGivwcMdU9z4/bDNvYlfk7YnC6Nv8MsJWjv5B0deDZF8CbS0RHzmfAh5zwpY5tDS +r26zAEzW0jxJ6EfvL546G5OcIr7L2nRgMBkHGdWsxmkxilzt/dk9tPAJoQd181BA +Zg6t51mR+rHfzJQ= +-----END CERTIFICATE----- |