Botan 1.10.17

cms_ealg.cpp
Go to the documentation of this file.
1 /*
2 * CMS Encoding Operations
3 * (C) 1999-2007 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7
8 #include <botan/cms_enc.h>
9 #include <botan/bigint.h>
10 #include <botan/cbc.h>
11 #include <botan/der_enc.h>
12 #include <botan/hash.h>
13 #include <botan/libstate.h>
14 #include <botan/oids.h>
15 #include <botan/pipe.h>
16 #include <botan/pubkey.h>
17 #include <memory>
18
19 namespace Botan {
20
21 namespace {
22
23 /*
24 * Choose an algorithm
25 */
26 std::string choose_algo(const std::string& user_algo,
27 const std::string& default_algo)
28 {
29 if(user_algo == "")
30 return global_state().deref_alias(default_algo);
31 return global_state().deref_alias(user_algo);
32 }
33
34 /*
35 * Encode a SignerIdentifier/RecipientIdentifier
36 */
37 DER_Encoder& encode_si(DER_Encoder& der, const X509_Certificate& cert,
38 bool use_skid_encoding = false)
39 {
40 if(cert.subject_key_id().size() && use_skid_encoding)
41 der.encode(cert.subject_key_id(), OCTET_STRING, ASN1_Tag(0));
42 else
43 {
44 der.start_cons(SEQUENCE).
45 encode(cert.issuer_dn()).
46 encode(BigInt::decode(cert.serial_number())).
47 end_cons();
48 }
49
50 return der;
51 }
52
53 /*
54 * Compute the hash of some content
55 */
56 SecureVector<byte> hash_of(const SecureVector<byte>& content,
57 const std::string& hash_name)
58 {
59 Algorithm_Factory& af = global_state().algorithm_factory();
60 std::auto_ptr<HashFunction> hash_fn(af.make_hash_function(hash_name));
61 return hash_fn->process(content);
62 }
63
64 /*
65 * Encode Attributes containing info on content
66 */
67 SecureVector<byte> encode_attr(const SecureVector<byte>& data,
68 const std::string& type,
69 const std::string& hash)
70 {
71 SecureVector<byte> digest = hash_of(data, hash);
72
73 DER_Encoder encoder;
74 encoder.encode(OIDS::lookup(type));
75 Attribute content_type("PKCS9.ContentType", encoder.get_contents());
76
77 encoder.encode(digest, OCTET_STRING);
78 Attribute message_digest("PKCS9.MessageDigest", encoder.get_contents());
79
80 encoder.start_cons(SET)
81 .encode(content_type)
82 .encode(message_digest)
83 .end_cons();
84
85 return encoder.get_contents();
86 }
87
88 }
89
90 /*
91 * Encrypt a message
92 */
93 void CMS_Encoder::encrypt(RandomNumberGenerator& rng,
94 const X509_Certificate& to,
95 const std::string user_cipher)
96 {
97 const std::string cipher = choose_algo(user_cipher, "TripleDES");
98
99 std::auto_ptr<Public_Key> key(to.subject_public_key());
100 const std::string algo = key->algo_name();
101
102 Key_Constraints constraints = to.constraints();
103
104 if(algo == "RSA")
105 {
106 if(constraints != NO_CONSTRAINTS && !(constraints & KEY_ENCIPHERMENT))
107 throw Invalid_Argument("CMS: Constraints not set for encryption");
108
109 encrypt_ktri(rng, to, key.get(), cipher);
110 }
111 else if(algo == "DH")
112 {
113 if(constraints != NO_CONSTRAINTS && !(constraints & KEY_AGREEMENT))
114 throw Invalid_Argument("CMS: Constraints not set for key agreement");
115
116 encrypt_kari(rng, to, key.get(), cipher);
117 }
118 else
119 throw Invalid_Argument("Unknown CMS PK encryption algorithm " + algo);
120 }
121
122 /*
123 * Encrypt a message with a key transport algo
124 */
125 void CMS_Encoder::encrypt_ktri(RandomNumberGenerator& rng,
126 const X509_Certificate& to,
127 Public_Key* pub_key,
128 const std::string& cipher)
129 {
130 const std::string padding = "EME-PKCS1-v1_5";
131 const std::string pk_algo = pub_key->algo_name();
132
133 PK_Encryptor_EME encryptor(*pub_key, padding);
134
135 SymmetricKey cek = setup_key(rng, cipher);
136
137 AlgorithmIdentifier alg_id(OIDS::lookup(pk_algo + '/' + padding),
138 AlgorithmIdentifier::USE_NULL_PARAM);
139
140 DER_Encoder encoder;
141
142 encoder.start_cons(SEQUENCE)
143 .encode(static_cast<size_t>(0))
144 .start_cons(SET)
145 .start_cons(SEQUENCE)
146 .encode(static_cast<size_t>(0));
147 encode_si(encoder, to)
148 .encode(alg_id)
149 .encode(encryptor.encrypt(cek.bits_of(), rng), OCTET_STRING)
150 .end_cons()
151 .end_cons()
152 .raw_bytes(do_encrypt(rng, cek, cipher))
153 .end_cons();
154
155 add_layer("CMS.EnvelopedData", encoder);
156 }
157
158 /*
159 * Encrypt a message with a key agreement algo
160 */
161 void CMS_Encoder::encrypt_kari(RandomNumberGenerator&,
162 const X509_Certificate&,
163 Public_Key*,
164 const std::string&)
165 {
166 throw Internal_Error("FIXME: unimplemented");
167
168 #if 0
169 SymmetricKey cek = setup_key(rng, cipher);
170
171 DER_Encoder encoder;
172 encoder.start_cons(SEQUENCE);
173 encoder.encode(2);
174 encoder.start_cons(SET);
175 encoder.start_sequence(ASN1_Tag(1));
176 encoder.encode(3);
177 encode_si(encoder, to);
178 encoder.encode(AlgorithmIdentifier(pk_algo + "/" + padding));
179 encoder.encode(encrypted_cek, OCTET_STRING);
180 encoder.end_cons();
181 encoder.end_cons();
182 encoder.raw_bytes(do_encrypt(rng, cek, cipher));
183 encoder.end_cons();
184
185 add_layer("CMS.EnvelopedData", encoder);
186 #endif
187 }
188
189 /*
190 * Encrypt a message with a shared key
191 */
192 void CMS_Encoder::encrypt(RandomNumberGenerator& rng,
193 const SymmetricKey& kek,
194 const std::string& user_cipher)
195 {
196 throw Internal_Error("FIXME: untested");
197
198 const std::string cipher = choose_algo(user_cipher, "TripleDES");
199 SymmetricKey cek = setup_key(rng, cipher);
200
201 SecureVector<byte> kek_id; // FIXME: ?
202
203 DER_Encoder encoder;
204
205 encoder.start_cons(SEQUENCE)
206 .encode(static_cast<size_t>(2))
207 .start_explicit(ASN1_Tag(2))
208 .encode(static_cast<size_t>(4))
209 .start_cons(SEQUENCE)
210 .encode(kek_id, OCTET_STRING)
211 .end_cons()
212 .encode(AlgorithmIdentifier(OIDS::lookup("KeyWrap." + cipher),
213 AlgorithmIdentifier::USE_NULL_PARAM))
214 .encode(wrap_key(rng, cipher, cek, kek), OCTET_STRING)
215 .end_cons()
216 .raw_bytes(do_encrypt(rng, cek, cipher))
217 .end_cons();
218
219 add_layer("CMS.EnvelopedData", encoder);
220 }
221
222 /*
223 * Encrypt a message with a passphrase
224 */
225 void CMS_Encoder::encrypt(RandomNumberGenerator&,
226 const std::string&,
227 const std::string& user_cipher)
228 {
229 const std::string cipher = choose_algo(user_cipher, "TripleDES");
230 throw Internal_Error("FIXME: unimplemented");
231 /*
232 SymmetricKey cek = setup_key(key);
233
234 DER_Encoder encoder;
235 encoder.start_cons(SEQUENCE);
236 encoder.encode(0);
237 encoder.raw_bytes(do_encrypt(rng, cek, cipher));
238 encoder.end_cons();
239
240 add_layer("CMS.EnvelopedData", encoder);
241 */
242 }
243
244 /*
245 * Encrypt the content with the chosen key/cipher
246 */
247 SecureVector<byte> CMS_Encoder::do_encrypt(RandomNumberGenerator& rng,
248 const SymmetricKey& key,
249 const std::string& cipher_name)
250 {
251 Algorithm_Factory& af = global_state().algorithm_factory();
252
253 const BlockCipher* cipher = af.prototype_block_cipher(cipher_name);
254
255 if(!cipher)
256 throw Invalid_Argument("CMS: Can't encrypt with non-existent cipher " + cipher_name);
257
258 if(!OIDS::have_oid(cipher->name() + "/CBC"))
259 throw Encoding_Error("CMS: No OID assigned for " + cipher_name + "/CBC");
260
261 InitializationVector iv(rng, cipher->block_size());
262
263 AlgorithmIdentifier content_cipher;
264 content_cipher.oid = OIDS::lookup(cipher->name() + "/CBC");
265 content_cipher.parameters = encode_params(cipher->name(), key, iv);
266
267 Pipe pipe(new CBC_Encryption(cipher->clone(), new PKCS7_Padding, key, iv));
268
269 pipe.process_msg(data);
270
271 DER_Encoder encoder;
272 encoder.start_cons(SEQUENCE);
273 encoder.encode(OIDS::lookup(type));
274 encoder.encode(content_cipher);
275 encoder.encode(pipe.read_all(), OCTET_STRING, ASN1_Tag(0));
276 encoder.end_cons();
277
278 return encoder.get_contents();
279 }
280
281 /*
282 * Sign a message
283 */
284 void CMS_Encoder::sign(const X509_Certificate& cert,
285 const Private_Key& key,
286 RandomNumberGenerator& rng,
287 const std::vector<X509_Certificate>& chain,
288 const std::string& hash,
289 const std::string& pad_algo)
290 {
291 std::string padding = pad_algo + "(" + hash + ")";
292
293 Signature_Format format = IEEE_1363;
294
295 PK_Signer signer(key, padding, format);
296
297 AlgorithmIdentifier sig_algo(OIDS::lookup(key.algo_name() + "/" + padding),
298 AlgorithmIdentifier::USE_NULL_PARAM);
299
300 SecureVector<byte> signed_attr = encode_attr(data, type, hash);
301 signer.update(signed_attr);
302 SecureVector<byte> signature = signer.signature(rng);
303 signed_attr[0] = 0xA0;
304
305 const size_t SI_VERSION = cert.subject_key_id().size() ? 3 : 1;
306 const size_t CMS_VERSION = (type != "CMS.DataContent") ? 3 : SI_VERSION;
307
308 DER_Encoder encoder;
309
310 encoder.start_cons(SEQUENCE)
311 .encode(CMS_VERSION)
312 .start_cons(SET)
313 .encode(AlgorithmIdentifier(OIDS::lookup(hash),
314 AlgorithmIdentifier::USE_NULL_PARAM))
315 .end_cons()
316 .raw_bytes(make_econtent(data, type));
317
318 encoder.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC);
319 for(size_t j = 0; j != chain.size(); j++)
320 encoder.raw_bytes(chain[j].BER_encode());
321 encoder.raw_bytes(cert.BER_encode()).end_cons();
322
323 encoder.start_cons(SET)
324 .start_cons(SEQUENCE)
325 .encode(SI_VERSION);
326 encode_si(encoder, cert, ((SI_VERSION == 3) ? true : false))
327 .encode(
328 AlgorithmIdentifier(OIDS::lookup(hash),
329 AlgorithmIdentifier::USE_NULL_PARAM)
330 )
331 .raw_bytes(signed_attr)
332 .encode(sig_algo)
333 .encode(signature, OCTET_STRING)
334 .end_cons()
335 .end_cons()
336 .end_cons();
337
338 add_layer("CMS.SignedData", encoder);
339 }
340
341 /*
342 * Digest a message
343 */
344 void CMS_Encoder::digest(const std::string& user_hash)
345 {
346 const std::string hash = choose_algo(user_hash, "SHA-1");
347 if(!OIDS::have_oid(hash))
348 throw Encoding_Error("CMS: No OID assigned for " + hash);
349
350 const size_t VERSION = (type != "CMS.DataContent") ? 2 : 0;
351
352 DER_Encoder encoder;
353 encoder.start_cons(SEQUENCE)
354 .encode(VERSION)
355 .encode(AlgorithmIdentifier(OIDS::lookup(hash),
356 AlgorithmIdentifier::USE_NULL_PARAM))
357 .raw_bytes(make_econtent(data, type))
358 .encode(hash_of(data, hash), OCTET_STRING)
359 .end_cons();
360
361 add_layer("CMS.DigestedData", encoder);
362 }
363
364 /*
365 * MAC a message with an encrypted key
366 */
367 void CMS_Encoder::authenticate(const X509_Certificate&,
368 const std::string& mac_algo)
369 {
370 const std::string mac = choose_algo(mac_algo, "HMAC(SHA-1)");
371 throw Internal_Error("FIXME: unimplemented");
372 }
373
374 /*
375 * MAC a message with a shared key
376 */
377 void CMS_Encoder::authenticate(const SymmetricKey&,
378 const std::string& mac_algo)
379 {
380 const std::string mac = choose_algo(mac_algo, "HMAC(SHA-1)");
381 throw Internal_Error("FIXME: unimplemented");
382 }
383
384 /*
385 * MAC a message with a passphrase
386 */
387 void CMS_Encoder::authenticate(const std::string&,
388 const std::string& mac_algo)
389 {
390 const std::string mac = choose_algo(mac_algo, "HMAC(SHA-1)");
391 throw Internal_Error("FIXME: unimplemented");
392 }
393
394 }
Botan::X509_Certificate::subject_key_id
MemoryVector< byte > subject_key_id() const
Definition: x509cert.cpp:258
Botan::DER_Encoder::get_contents
SecureVector< byte > get_contents()
Definition: der_enc.cpp:122
Botan::CONTEXT_SPECIFIC
Definition: asn1_int.h:22
Botan::Algorithm_Factory
Definition: algo_factory.h:34
Botan::OctetString
Definition: symkey.h:19
Botan::DER_Encoder::raw_bytes
DER_Encoder & raw_bytes(const byte val[], size_t len)
Definition: der_enc.cpp:188
Botan::RandomNumberGenerator
Definition: rng.h:20
Botan::Library_State::algorithm_factory
Algorithm_Factory & algorithm_factory() const
Definition: libstate.cpp:173
Botan::Private_Key
Definition: pk_keys.h:86
Botan::PK_Signer::signature
SecureVector< byte > signature(RandomNumberGenerator &rng)
Definition: pubkey.cpp:210
Botan::Signature_Format
Signature_Format
Definition: pubkey.h:24
Botan::BlockCipher::clone
virtual BlockCipher * clone() const =0
Botan::Internal_Error
Definition: exceptn.h:45
Botan::Algorithm_Factory::prototype_block_cipher
const BlockCipher * prototype_block_cipher(const std::string &algo_spec, const std::string &provider="")
Definition: algo_factory.cpp:193
Botan::KEY_ENCIPHERMENT
Definition: pubkey_enums.h:22
Botan::Public_Key::algo_name
virtual std::string algo_name() const =0
Botan::CMS_Encoder::digest
void digest(const std::string &="")
Definition: cms_ealg.cpp:344
Botan::Invalid_Argument
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
Botan::KEY_AGREEMENT
Definition: pubkey_enums.h:24
Botan::DER_Encoder::start_explicit
DER_Encoder & start_explicit(u16bit type_tag)
Definition: der_enc.cpp:159
Botan::DER_Encoder::end_cons
DER_Encoder & end_cons()
Definition: der_enc.cpp:145
Botan::CMS_Encoder::encrypt
void encrypt(RandomNumberGenerator &, const X509_Certificate &, const std::string="")
Definition: cms_ealg.cpp:93
Botan::X509_Certificate::constraints
Key_Constraints constraints() const
Definition: x509cert.cpp:225
Botan::X509_Object::BER_encode
MemoryVector< byte > BER_encode() const
Definition: x509_obj.cpp:100
Botan::NO_CONSTRAINTS
Definition: pubkey_enums.h:19
Botan::SymmetricKey
OctetString SymmetricKey
Definition: symkey.h:147
Botan::CBC_Encryption
Definition: cbc.h:21
Botan::DER_Encoder::encode
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:209
Botan::OCTET_STRING
Definition: asn1_int.h:31
Botan::DER_Encoder
Definition: der_enc.h:22
Botan::X509_Certificate
Definition: x509cert.h:23
Botan::CMS_Encoder::sign
void sign(const X509_Certificate &cert, const Private_Key &key, RandomNumberGenerator &rng, const std::vector< X509_Certificate > &cert_chain, const std::string &hash, const std::string &padding)
Definition: cms_ealg.cpp:284
Botan::Global_State_Management::global_state
Library_State & global_state()
Definition: global_state.cpp:32
Botan::OIDS::lookup
std::string lookup(const OID &oid)
Definition: oids.cpp:31
Botan::ASN1_Tag
ASN1_Tag
Definition: asn1_int.h:19
Botan::AlgorithmIdentifier::oid
OID oid
Definition: alg_id.h:35
Botan::SEQUENCE
Definition: asn1_int.h:35
Botan
Definition: algo_base.h:14
Botan::Algorithm::name
virtual std::string name() const =0
Botan::PK_Encryptor_EME
Definition: pubkey.h:398
Botan::Public_Key
Definition: pk_keys.h:21
Botan::IEEE_1363
Definition: pubkey.h:24
Botan::MemoryRegion::size
size_t size() const
Definition: secmem.h:29
Botan::SET
Definition: asn1_int.h:36
Botan::PEM_Code::encode
std::string encode(const byte der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:19
Botan::Library_State::deref_alias
std::string deref_alias(const std::string &alias) const
Definition: libstate.cpp:162
Botan::X509_Certificate::subject_public_key
Public_Key * subject_public_key() const
Definition: x509cert.cpp:196
Botan::PKCS7_Padding
Definition: mode_pad.h:72
Botan::BigInt::decode
static BigInt decode(const byte buf[], size_t length, Base base=Binary)
Definition: big_code.cpp:102
Botan::AlgorithmIdentifier
Definition: alg_id.h:20
Botan::DER_Encoder::start_cons
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:135
Botan::SecureVector< byte >
Botan::Pipe
Definition: pipe.h:25
Botan::AlgorithmIdentifier::USE_NULL_PARAM
Definition: alg_id.h:23
Botan::PK_Signer
Definition: pubkey.h:123
Botan::OIDS::have_oid
bool have_oid(const std::string &name)
Definition: oids.cpp:61
Botan::OctetString::bits_of
SecureVector< byte > bits_of() const
Definition: symkey.h:30
Botan::Key_Constraints
Key_Constraints
Definition: pubkey_enums.h:18
Botan::CMS_Encoder::authenticate
void authenticate(const X509_Certificate &, const std::string &="")
Definition: cms_ealg.cpp:367
Botan::Encoding_Error
Definition: exceptn.h:129
Botan::BlockCipher::block_size
virtual size_t block_size() const =0
Botan::PK_Signer::update
void update(byte in)
Definition: pubkey.h:150
Botan::BlockCipher
Definition: block_cipher.h:18