Botan  1.10.9
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 
16 namespace Botan {
17 
18 namespace {
19 
20 /*
21 * Compute the hash of some content
22 */
23 SecureVector<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 
29  Algorithm_Factory& af = global_state().algorithm_factory();
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 */
38 std::vector<X509_Certificate> get_cert(BER_Decoder& signer_info,
39  X509_Store&)
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 */
73 void 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 */
108 SecureVector<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 */
159 void 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 decode(BER_Decoder &source, Key_Constraints &key_usage)
Library_State & global_state()
std::string lookup(const OID &oid)
Definition: oids.cpp:31
ASN1_Tag
Definition: asn1_int.h:19