scclib
Stable Cloud Computing C++ Library
cert.cc
1 /*
2 BSD 3-Clause License
3 
4 Copyright (c) 2022, Stable Cloud Computing, Inc.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9 1. Redistributions of source code must retain the above copyright notice, this
10  list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright notice,
13  this list of conditions and the following disclaimer in the documentation
14  and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <crypto/cert.h>
32 #include <map>
33 #include <sstream>
34 #include <iomanip>
35 #include <memory>
36 #include <system_error>
37 #include <iostream>
38 #include <algorithm>
39 
40 using namespace scc::crypto;
41 
42 static void throw_err(const std::string& msg)
43 {
44  throw std::runtime_error(msg);
45 }
46 
47 static oid_value s_rsa_key = {1, 2, 840, 113549, 1, 1, 1};
48 static oid_value s_ec_key = {1, 2, 840, 10045, 2, 1};
49 static std::map<KeyAlgoType, oid_value> s_ec_param =
50 {
51  {KeyAlgoType::ec_p192r1, {1, 2, 840, 10045, 3, 1, 1}},
52  {KeyAlgoType::ec_p224r1, {1, 3, 132, 0, 33}},
53  {KeyAlgoType::ec_p256r1, {1, 2, 840, 10045, 3, 1, 7}},
54  {KeyAlgoType::ec_p384r1, {1, 3, 132, 0, 34}},
55  {KeyAlgoType::ec_p521r1, {1, 3, 132, 0, 35}},
56 };
57 
58 std::ostream& operator<<(std::ostream& os, const scc::crypto::KeyAlgoType& algo)
59 {
60  std::stringstream s;
61  switch (algo)
62  {
63  case KeyAlgoType::rsa:
64  s << "rsa"; break;
66  s << "ecdsa 192"; break;
68  s << "ecdsa 224"; break;
70  s << "ecdsa 256"; break;
72  s << "ecdsa 384"; break;
74  s << "ecdsa 521"; break;
75  case KeyAlgoType::unknown:
76  s << "unknown"; break;
77  }
78  os.write(s.str().c_str(), s.str().size());
79  return os;
80 }
81 
83 {
84  if (algorithm_id == s_rsa_key && parameters != nullptr && parameters->is_null())
85  {
86  return KeyAlgoType::rsa;
87  }
88  else if (algorithm_id == s_ec_key && parameters != nullptr && parameters->is_object_id())
89  {
90  auto it = std::find_if(s_ec_param.begin(), s_ec_param.end(), [&](auto& i)
91  {
92  return parameters->object_id() == i.second;
93  });
94 
95  if (it != s_ec_param.end()) return it->first;
96  }
97 
98  return KeyAlgoType::unknown;
99 }
100 
101 void PublicKeyCert::parse(const BasePtr base)
102 {
103  algorithm_id.clear();
104  parameters.reset();
105  public_key.clear();
106 
107  if (!base || !base->is_seq()) throw_err("PublicKeyInfoCert parse: base not a sequence");
108  if (base->contain().size() != 2 ) throw_err("PublicKeyInfoCert parse: wrong base sequence size");
109 
110  if (!base->contain()[0]->is_seq()) throw_err("PublicKeyInfoCert parse: missing algorithm id element");
111  if (!base->contain()[1]->is_bit_string()) throw_err("PublicKeyInfoCert parse: missing public key element");
112 
113  auto& seq = base->contain()[0]->contain();
114 
115  if (!seq.size() || seq.size() > 2) throw_err("PublicKeyInfoCert parse: algorithm id empty");
116 
117  if (!seq[0]->is_object_id()) throw_err("PublicKeyInfoCert parse: algorithm element not oid");
118  algorithm_id = seq[0]->object_id();
119 
120  if (seq.size() == 2)
121  {
122  // store the parameters as a new element
123  SecVecUchar v;
124  DerDocument::dump_element(seq[1], v);
126  }
127 
128  // the public key is stored as DER-encoded bytes
129  auto bits = base->contain()[1]->bit_string();
130  bits.get(public_key);
131 }
132 
133 BasePtr PublicKeyCert::dump() const
134 {
135  auto seq = new DerSequence;
136  BasePtr base(seq);
137 
138  auto algseq = new DerSequence;
139  seq->emplace_back(algseq);
140 
141  auto oid = new DerObjectIdentifier;
142  algseq->emplace_back(oid);
143  oid->set(algorithm_id);
144 
145  if (parameters != nullptr)
146  {
147  SecVecUchar v;
149  algseq->push_back(DerDocument::parse_element(v));
150  }
151 
152  auto bits = new DerBitString;
153  seq->emplace_back(bits);
154  bits->set(public_key, public_key.size()*8);
155 
156  return base;
157 }
158 
159 std::string PublicKeyCert::str() const
160 {
161  using std::endl;
162 
163  std::stringstream s;
164 
165  s << "pub key info: " << type() << " id: " << algorithm_id;
166  if (parameters != nullptr && parameters->is_object_id()) s << " param: " << parameters->object_id();
167  if (parameters != nullptr && parameters->is_null()) s << " param: null";
168  s << " size: " << public_key.size();
169  return s.str();
170 }
171 
173 {
174  if (type() != KeyAlgoType::rsa) throw_err("PublicKeyInfoCert get rsa: wrong algorithm type");
175 
176  BasePtr certseq = DerDocument::parse_element(public_key, 0);
177 
178  RsaPublicKeyCert::parse(certseq, key);
179 }
180 
182 {
183  algorithm_id = s_rsa_key;
184  parameters.reset(new DerNull);
185 
186  auto base = RsaPublicKeyCert::dump(key);
187 
188  public_key.clear();
190 }
191 
192 #include "encode/hex.h"
193 
195 {
196  auto t = type();
197 
198  if (t == KeyAlgoType::unknown || t == KeyAlgoType::rsa) throw_err("PublicKeyCert get ec: wrong algorithm type");
199 
201 
202 //std::cout << "**** EC GET algo-" << algorithm_id << std::endl;
203 //std::cout << "**** EC GET params=" << DerDocument::print_element(parameters) << std::endl;
204 //std::cout << "**** EC GET public_key size=" << public_key.size() << " hex: " << scc::encode::bin_to_hexstr(public_key.data(), public_key.size(), ":", 16) << std::endl;
205 }
206 
207 void PublicKeyCert::set(const KeyAlgoType& algo, const EccGfpPoint& key)
208 {
209  if (algo == KeyAlgoType::unknown || algo == KeyAlgoType::rsa) throw_err("PublicKeyCert set ec: wrong algorithm type");
210 
211  algorithm_id = s_ec_key;
212 
213  auto oid = new DerObjectIdentifier;
214  parameters.reset(oid);
215  auto it = s_ec_param.find(algo);
216  if (it == s_ec_param.end()) throw_err("PublicKeyCert set ec: algorithm error");
217  oid->data() = it->second;
218 
219  public_key.clear();
220  EcPublicKeyCert::dump(key, public_key); // set the binary data directly to the key
221 
222 //std::cout << "**** EC GET algo=" << algorithm_id << std::endl;
223 //std::cout << "**** EC SET params=" << DerDocument::print_element(parameters) << std::endl;
224 //std::cout << "**** EC SET public_key size=" << public_key.size() << " hex: " << scc::encode::bin_to_hexstr(public_key.data(), public_key.size(), ":", 16) << std::endl;
225 
226 }
227 
228 void RsaPublicKeyCert::parse(const BasePtr& base, RsaPublicKey& key)
229 {
230  if (!base || !base->is_seq()) throw_err("rsa pub cert parse: base element not sequence");
231 
232  auto& seq = base->contain();
233 
234  if (seq.size() != 2) throw_err("rsa pub cert parse: size error");
235 
236  if (!seq[0]->is_integer() || !seq[1]->is_integer()) throw_err("rsa pub cert parse: element error");
237 
238  key.set(seq[0]->integer(), seq[1]->integer());
239 }
240 
242 {
243  auto seq = new DerSequence;
244  BasePtr base(seq);
245 
246  Bignum n, e;
247  key.get(n, e);
248 
249  BasePtr np(new DerInteger), ep(new DerInteger);
250  np->integer() = n;
251  ep->integer() = e;
252 
253  seq->push_back(np);
254  seq->push_back(ep);
255 
256  return base;
257 }
258 
259 void RsaPrivateKeyCert::parse(const BasePtr& base, RsaPrivateKey& key)
260 {
261  if (!base || !base->is_seq()) throw_err("rsa priv cert parse: base element not sequence");
262 
263  auto seq = base->contain();
264 
265  if (seq.size() != 9) throw_err("rsa priv cert parse: size error");
266 
267  if ( !seq[0]->is_integer() || !seq[1]->is_integer() || !seq[2]->is_integer()
268  || !seq[3]->is_integer() || !seq[4]->is_integer() || !seq[5]->is_integer()
269  || !seq[6]->is_integer() || !seq[7]->is_integer() || !seq[8]->is_integer())
270  {
271  throw_err("private key parse: data type error");
272  }
273 
274  if (seq[0]->integer() != 0) throw_err("private key parse: version error");
275 
276  key.set(seq[1]->integer(), seq[2]->integer(), seq[3]->integer(), seq[4]->integer(),
277  seq[5]->integer(), seq[6]->integer(), seq[7]->integer(), seq[8]->integer());
278 }
279 
281 {
282  Bignum n, e, d, p, q, ep, eq, qinv;
283  key.get(n, e, d, p, q, ep, eq, qinv);
284 
285  auto *seq = new DerSequence;
286  BasePtr ret(seq);
287 
288  DerInteger *ver_p = new DerInteger, *n_p = new DerInteger, *e_p = new DerInteger, *d_p = new DerInteger,
289  *p_p = new DerInteger, *q_p = new DerInteger, *ep_p = new DerInteger, *eq_p = new DerInteger, *qinv_p = new DerInteger;
290 
291  seq->emplace_back(ver_p);
292  seq->emplace_back(n_p);
293  seq->emplace_back(e_p);
294  seq->emplace_back(d_p);
295  seq->emplace_back(p_p);
296  seq->emplace_back(q_p);
297  seq->emplace_back(ep_p);
298  seq->emplace_back(eq_p);
299  seq->emplace_back(qinv_p);
300 
301  n_p->data() = n;
302  e_p->data() = e;
303  d_p->data() = d;
304  p_p->data() = p;
305  q_p->data() = q;
306  ep_p->data() = ep;
307  eq_p->data() = eq;
308  qinv_p->data() = qinv;
309 
310  return ret;
311 }
312 
313 void EcParametersCert::parse(const BasePtr& b, KeyAlgoType& algo)
314 {
315  if (!b || !b->is_object_id()) throw_err("ec params parse: base element not oid");
316 
317  auto it = std::find_if(s_ec_param.begin(), s_ec_param.end(), [&b](auto& i)
318  {
319  return b->object_id() == i.second;
320  });
321 
322  if (it != s_ec_param.end()) algo = it->first;
323  else algo = KeyAlgoType::unknown;
324 }
325 
327 {
328  auto it = s_ec_param.find(algo);
329 
330  if (it == s_ec_param.end()) throw_err("ec params dump: invalid algorithm");
331 
332  auto oid = new DerObjectIdentifier;
333  BasePtr ret(oid);
334  oid->data() = it->second;
335 
336  return ret;
337 }
338 
339 void EcPublicKeyCert::parse(const void* loc, int len, const KeyAlgoType& algo, EccGfpPoint& pub)
340 {
341  char* b = (char*)loc;
342 
343  if (len < 2 || b == nullptr || *b != '\x04') throw_err("ec public key parse: data error");
344 
345  EccGfp curve;
346  switch (algo)
347  {
349  curve.reset(EccGfp::Type::std_p192r1); break;
351  curve.reset(EccGfp::Type::std_p224r1); break;
353  curve.reset(EccGfp::Type::std_p256r1); break;
355  curve.reset(EccGfp::Type::std_p384r1); break;
357  curve.reset(EccGfp::Type::std_p521r1); break;
358  case KeyAlgoType::rsa:
359  case KeyAlgoType::unknown:
360  throw_err("ec public key parse: invalid algorithm");
361  }
362 
363  pub.set(b+1, len-1, curve);
364 }
365 
366 void EcPublicKeyCert::parse(const BasePtr& b, const KeyAlgoType& algo, EccGfpPoint& pub)
367 {
368  if (!b || !b->is_bit_string()) throw_err("ec public key parse: not bit string");
369 
370  SecVecChar v;
371  b->bit_string().get(v);
372  parse(v, algo, pub);
373 }
374 
376 {
377  SecVecChar v;
378  pub.get(v);
379 
380  v.insert(v.begin(), '\x04'); // uncompressed byte
381 
382  auto bst = new DerBitString;
383  BasePtr ret(bst);
384  bst->set(v, v.size()*8);
385 
386  return ret;
387 }
388 
389 void EcPublicKeyCert::dump(const EccGfpPoint& pub, std::vector<uint8_t>& uv)
390 {
391  SecVecChar v;
392  pub.get(v);
393  v.insert(v.begin(), '\x04');
394 
395  uv.clear();
396  uv.insert(uv.begin(), v.begin(), v.end());
397 }
398 
399 void EcPublicKeyCert::dump(const EccGfpPoint& pub, std::vector<char>& v)
400 {
401  pub.get(v);
402  v.insert(v.begin(), '\x04');
403 }
404 
405 void EcPrivateKeyCert::parse(const BasePtr& b, Bignum& priv, KeyAlgoType& algo, EccGfpPoint& pub)
406 {
407  if (!b || !b->is_seq()) throw_err("ec private parse: base not sequence");
408 
409  if (b->contain().size() != 4) throw_err("ec private parse: wrong sequence size");
410 
411  auto& seq = b->contain();
412 
413  if (!seq[0]->is_integer() || seq[0]->integer() != 1) throw_err("ec private parse: version error");
414 
415  if (!seq[1]->is_octet_string()) throw_err("ec private parse: private key error");
416 
417  SecVecChar v;
418  seq[1]->string_get(v);
419 
420  priv.set(v.data(), v.size());
421 
422  if (!seq[2]->context_class() || seq[2]->id() != 0) throw_err("ec private parse: param error");
423  BasePtr oid = DerBase::context_to_explicit(seq[2]);
424  EcParametersCert::parse(oid, algo);
425 
426  if (!seq[3]->context_class() || seq[3]->id() != 1) throw_err("ec private parse: pub key error");
427  BasePtr pkey = DerBase::context_to_explicit(seq[3]);
428  EcPublicKeyCert::parse(pkey, algo, pub);
429 }
430 
431 BasePtr EcPrivateKeyCert::dump(const Bignum& priv, const KeyAlgoType& algo, const EccGfpPoint& pub)
432 {
433  auto seq = new DerSequence;
434  BasePtr ret(seq);
435 
436  auto ver = new DerInteger;
437  seq->emplace_back(ver);
438  ver->data() = 1;
439 
440  SecVecChar v;
441  v.resize(priv.len());
442  priv.get(v.data(), v.size());
443  auto pk = new DerOctetString;
444  seq->emplace_back(pk);
445  pk->set(v);
446 
447  BasePtr oid = EcParametersCert::dump(algo);
448  seq->push_back(DerBase::explicit_to_context(oid, 0));
449 
450  BasePtr bst = EcPublicKeyCert::dump(pub);
451  seq->push_back(DerBase::explicit_to_context(bst, 1));
452 
453  return ret;
454 }
X.509 and RSA certificates.
Big number.
Definition: bignum.h:59
void get(void *, int) const
Octal (byte) output of a positive number.
void set(uint32_t)
Set to a word.
int len() const
Required length of get() output in bytes.
void set(const std::vector< uint8_t > &v, size_t w)
Set the bit string from a bit string input.
Definition: der.h:114
static BasePtr explicit_to_context(const BasePtr &BasePtr, uint32_t)
Convert explicit to context.
Definition: der.cc:1057
static BasePtr context_to_explicit(const BasePtr &)
Change a context element to explicit.
Definition: der.cc:1048
static void dump_element(const BasePtr &, std::vector< uint8_t > &)
Dump an element to a data vector.
Definition: der.cc:1231
static BasePtr parse_element(const std::vector< uint8_t > &, size_t=0)
Parse an element from a data vector.
Definition: der.cc:1171
scc::crypto::Bignum & data()
Return the integer (an scc::crypto::Bignum)
Definition: der.h:798
Object identifier class.
Definition: der.h:555
void set(const oid_value &v)
Set oid values.
Definition: der.cc:649
An ASN.1 SEQUENCE or SEQUENCE OF type.
Definition: der.h:487
void get(scc::crypto::Bignum &, scc::crypto::Bignum &) const
Get the coordinates.
void set(const scc::crypto::Bignum &, const scc::crypto::Bignum &)
Set point.
Elliptic curve cryptography over Galois prime field GF(p) curve.
Definition: ecc.h:77
void reset(Type type)
Reset the curve to a new standard type.
@ std_p224r1
standard curve secp224r1 (112 bit security level)
@ std_p192r1
standard curve secp192r1 (96 bit security level)
@ std_p256r1
standard curve secp256r1 (128 bit security level)
@ std_p521r1
standard curve secp521r1 (256 bit security level)
@ std_p384r1
standard curve secp384r1 (192 bit security level)
RSA Private Key.
Definition: rsa.h:185
RSA Public Key.
Definition: rsa.h:69
void resize(typename std::vector< T >::size_type)
Resize the vector.
Definition: secvec.cc:59
void clear() noexcept
Zero the original vector and clear it.
Definition: secvec.cc:52
KeyAlgoType
Key algorithm type.
Definition: cert.h:78
@ ec_p192r1
parameter {1, 2, 840, 10045, 3, 1, 1}
Definition: cert.h:81
@ ec_p256r1
parameter {1, 2, 840, 10045, 3, 1, 7}
Definition: cert.h:83
@ ec_p384r1
parameter {1, 3, 132, 0, 34}
Definition: cert.h:84
@ rsa
parameter null
Definition: cert.h:80
@ ec_p224r1
parameter {1, 3, 132, 0, 33}
Definition: cert.h:82
@ ec_p521r1
parameter {1, 3, 132, 0, 35}
Definition: cert.h:85
Binary to hex string converter.
std::ostream & operator<<(std::ostream &, const scc::net::InetAddr &)
Print the socket address details to an output stream.
Definition: inet.cc:320
static void parse(const BasePtr &, KeyAlgoType &)
Parse from an object id.
Definition: cert.cc:313
static BasePtr dump(const KeyAlgoType &)
Dump to an object id.
Definition: cert.cc:326
static BasePtr dump(const Bignum &, const KeyAlgoType &, const EccGfpPoint &)
Dump to a sequence.
Definition: cert.cc:431
static void parse(const BasePtr &, Bignum &, KeyAlgoType &, EccGfpPoint &)
Parse from a sequence.
Definition: cert.cc:405
static void parse(const BasePtr &, const KeyAlgoType &, EccGfpPoint &)
Parse from a bit string for a specific curve.
Definition: cert.cc:366
static BasePtr dump(const EccGfpPoint &)
Dump to an uncompressed bit string.
Definition: cert.cc:375
BasePtr dump() const
Dump to a sequence.
Definition: cert.cc:133
void parse(const BasePtr)
Parse from a sequence.
Definition: cert.cc:101
void set(const RsaPublicKey &key)
Set rsa public key.
Definition: cert.cc:181
KeyAlgoType type() const
Return the embedded public key type.
Definition: cert.cc:82
std::vector< uint8_t > public_key
The uninterpreted public key.
Definition: cert.h:111
BasePtr parameters
The optional parameters (may be null)
Definition: cert.h:110
std::string str() const
Print descriptive string.
Definition: cert.cc:159
oid_value algorithm_id
Algorithm id.
Definition: cert.h:109
void get(RsaPublicKey &key) const
Get rsa public key.
Definition: cert.cc:172
static BasePtr dump(const RsaPrivateKey &)
Dump to a sequence.
Definition: cert.cc:280
static void parse(const BasePtr &, RsaPrivateKey &)
Parse from a sequence.
Definition: cert.cc:259
static BasePtr dump(const RsaPublicKey &)
Dump to a sequence.
Definition: cert.cc:241
static void parse(const BasePtr &, RsaPublicKey &)
Parse from a sequence.
Definition: cert.cc:228