Botan 1.10.17
cms_dalg.cpp
Go to the documentation of this file.
1/*
2* CMS Decoding Operations
3* (C) 1999-2007 Jack Lloyd
4*
5* Distributed under the terms of the Botan license
6*/
7
8#include <botan/cms_dec.h>
9#include <botan/ber_dec.h>
10#include <botan/oids.h>
11#include <botan/hash.h>
12#include <botan/bigint.h>
13#include <botan/libstate.h>
14#include <memory>
15
16namespace Botan {
17
18namespace {
19
20/*
21* Compute the hash of some content
22*/
23SecureVector<byte> hash_of(const SecureVector<byte>& content,
24 const AlgorithmIdentifier& hash_algo,
25 std::string& hash_name)
26 {
27 hash_name = OIDS::lookup(hash_algo.oid);
28
30
31 std::auto_ptr<HashFunction> hash_fn(af.make_hash_function(hash_name));
32 return hash_fn->process(content);
33 }
34
35/*
36* Find a cert based on SignerIdentifier
37*/
38std::vector<X509_Certificate> get_cert(BER_Decoder& signer_info,
40 {
41 BER_Object id = signer_info.get_next_object();
42
43 std::vector<X509_Certificate> found;
44
45#if 0
46 if(id.type_tag == SEQUENCE && id.class_tag == CONSTRUCTED)
47 {
48 X509_DN issuer;
49 BigInt serial;
50 BER_Decoder iands(id.value);
51 iands.decode(issuer);
52 iands.decode(serial);
53
54 found = store.get_certs(IandS_Match(issuer, BigInt::encode(serial)));
55 }
56 else if(id.type_tag == 0 && id.class_tag == CONSTRUCTED)
57 found = store.get_certs(SKID_Match(id.value));
58 else
59 throw Decoding_Error("CMS: Unknown tag for cert identifier");
60#endif
61 throw Internal_Error("Not implemented");
62
63 // verify cert if found
64
65 if(found.size() > 1)
66 throw Internal_Error("CMS: Found more than one match in get_cert");
67 return found;
68 }
69
70/*
71* Read OriginatorInfo
72*/
73void read_orig_info(BER_Decoder& info, X509_Store& store)
74 {
75 BER_Object next = info.get_next_object();
76
77 if(next.type_tag == 0 &&
78 next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
79 {
80 DataSource_Memory certs(next.value);
81 while(!certs.end_of_data())
82 {
83 // FIXME: can be attribute certs too
84 // FIXME: DoS?
85 X509_Certificate cert(certs);
86 store.add_cert(cert);
87 }
88 next = info.get_next_object();
89 }
90 if(next.type_tag == 1 &&
91 next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
92 {
93 DataSource_Memory crls(next.value);
94 while(!crls.end_of_data())
95 {
96 // FIXME: DoS?
97 X509_CRL crl(crls);
98 store.add_crl(crl);
99 }
100 next = info.get_next_object();
101 }
102 info.push_back(next);
103 }
104
105/*
106* Decode any Attributes, and check type
107*/
108SecureVector<byte> decode_attributes(BER_Decoder& ber, const OID& type,
109 bool& bad_attributes)
110 {
111 BER_Object obj = ber.get_next_object();
112 SecureVector<byte> digest;
113
114 bool got_digest = false;
115 bool got_content_type = false;
116
117 if(obj.type_tag == 0 &&
118 obj.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
119 ber.push_back(obj);
120 else
121 {
122 BER_Decoder attributes(obj.value);
123 while(attributes.more_items())
124 {
125 Attribute attr;
126 attributes.decode(attr);
127 BER_Decoder attr_value(attr.parameters);
128
129 if(attr.oid == OIDS::lookup("PKCS9.MessageDigest"))
130 {
131 got_digest = true;
132 attr_value.decode(digest, OCTET_STRING);
133 }
134 else if(attr.oid == OIDS::lookup("PKCS9.ContentType"))
135 {
136 got_content_type = true;
137 OID inner_type;
138 attr_value.decode(inner_type);
139 if(inner_type != type)
140 bad_attributes = true;
141 }
142 else
143 throw Decoding_Error("Unknown/unhandled CMS attribute found: " +
144 OIDS::lookup(attr.oid));
145 }
146
147 if(!got_digest || !got_content_type)
148 bad_attributes = true;
149 }
150
151 return digest;
152 }
153
154}
155
156/*
157* Decode this layer of CMS encoding
158*/
159void CMS_Decoder::decode_layer()
160 {
161 try {
162 if(status == FAILURE)
163 throw Invalid_State("CMS: Decoder is in FAILURE state");
164
165 status = GOOD;
166 info = "";
167
168 type = next_type;
169
170 if(type == OIDS::lookup("CMS.DataContent"))
171 return;
172
173 BER_Decoder decoder(data);
174 if(type == OIDS::lookup("CMS.CompressedData"))
175 decompress(decoder);
176 else if(type == OIDS::lookup("CMS.DigestedData"))
177 {
178 size_t version;
179 AlgorithmIdentifier hash_algo;
180 SecureVector<byte> digest;
181
182 BER_Decoder hash_info = decoder.start_cons(SEQUENCE);
183
184 hash_info.decode(version);
185 if(version != 0 && version != 2)
186 throw Decoding_Error("CMS: Unknown version for DigestedData");
187
188 hash_info.decode(hash_algo);
189 read_econtent(hash_info);
190 hash_info.decode(digest, OCTET_STRING);
191 hash_info.end_cons();
192
193 if(digest != hash_of(data, hash_algo, info))
194 status = BAD;
195 }
196 else if(type == OIDS::lookup("CMS.SignedData"))
197 {
198#if 1
199 throw Internal_Error("FIXME: not implemented");
200#else
201 size_t version;
202
203 BER_Decoder sig_info = BER::get_subsequence(decoder);
204 BER::decode(sig_info, version);
205 if(version != 1 && version != 3)
206 throw Decoding_Error("CMS: Unknown version for SignedData");
207 BER::get_subset(sig_info); // hash algos (do something with these?)
208 read_econtent(sig_info);
209 read_orig_info(sig_info, store);
210
211 BER_Decoder signer_infos = BER::get_subset(sig_info);
212 while(signer_infos.more_items())
213 {
214 AlgorithmIdentifier sig_algo, hash_algo;
215 SecureVector<byte> signature, digest;
216 size_t version;
217
218 BER_Decoder signer_info = BER::get_subsequence(signer_infos);
219 BER::decode(signer_info, version);
220 if(version != 1 && version != 3)
221 throw Decoding_Error("CMS: Unknown version for SignerInfo");
222
223 std::vector<X509_Certificate> certs = get_cert(signer_info, store);
224 if(certs.size() == 0) { status = NO_KEY; continue; }
225
226 BER::decode(signer_info, hash_algo);
227 bool bad_attr = false;
228 digest = decode_attributes(signer_info, next_type, bad_attr);
229 if(bad_attr) { status = BAD; continue; }
230 BER::decode(signer_info, sig_algo);
231 BER::decode(signer_info, signature, OCTET_STRING);
232 // unsigned attributes
233 signer_info.verify_end();
234
235 if(digest.has_items())
236 {
237 std::string hash;
238 if(digest != hash_of(data, hash_algo, hash))
239 {
240 status = BAD;
241 continue;
242 }
243 status = check_sig(signed_attr, sig_algo, signature, certs[0]);
244 }
245 else
246 status = check_sig(data, sig_algo, signature, certs[0]);
247
248 if(status == BAD)
249 continue;
250
251 // fix this (gets only last signer, for one thing)
252 // maybe some way for the user to get all certs that signed the
253 // message? that would be useful
254 info = "CN=" + cert.subject_info("CommonName") +
255 ",O=" + cert.subject_info("Organization") +
256 ",OU=" + cert.subject_info("Organizational Unit");
257 }
258#endif
259 }
260 else if(type == OIDS::lookup("CMS.EnvelopedData"))
261 {
262 throw Internal_Error("FIXME: not implemented");
263 }
264 else if(type == OIDS::lookup("CMS.AuthenticatedData"))
265 {
266 throw Internal_Error("FIXME: not implemented");
267 }
268 else
269 throw Decoding_Error("CMS: Unknown content ID " + type.as_string());
270 }
271 catch(std::exception)
272 {
273 status = FAILURE;
274 }
275 }
276
277}
static SecureVector< byte > encode(const BigInt &n, Base base=Binary)
Definition big_code.cpp:64
Algorithm_Factory & algorithm_factory() const
Definition libstate.cpp:173
void push_back(T x)
Definition secmem.h:149
void decode(BER_Decoder &source, Key_Constraints &key_usage)
std::string lookup(const OID &oid)
Definition oids.cpp:31
ASN1_Tag
Definition asn1_int.h:19
@ CONSTRUCTED
Definition asn1_int.h:25
@ SEQUENCE
Definition asn1_int.h:35
@ CONTEXT_SPECIFIC
Definition asn1_int.h:22
@ OCTET_STRING
Definition asn1_int.h:31
Library_State & global_state()
Decoding_Error(const std::string &name)
Definition exceptn.h:140
Internal_Error(const std::string &err)
Definition exceptn.h:47
Invalid_State(const std::string &err)
Definition exceptn.h:27