aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/cert/cvc
diff options
context:
space:
mode:
authorlloyd <[email protected]>2014-01-10 03:41:59 +0000
committerlloyd <[email protected]>2014-01-10 03:41:59 +0000
commit6894dca64c04936d07048c0e8cbf7e25858548c3 (patch)
tree5d572bfde9fe667dab14e3f04b5285a85d8acd95 /src/lib/cert/cvc
parent9efa3be92442afb3d0b69890a36c7f122df18eda (diff)
Move lib into src
Diffstat (limited to 'src/lib/cert/cvc')
-rw-r--r--src/lib/cert/cvc/asn1_eac_str.cpp127
-rw-r--r--src/lib/cert/cvc/asn1_eac_tm.cpp293
-rw-r--r--src/lib/cert/cvc/cvc_ado.cpp127
-rw-r--r--src/lib/cert/cvc/cvc_ado.h98
-rw-r--r--src/lib/cert/cvc/cvc_cert.cpp135
-rw-r--r--src/lib/cert/cvc/cvc_cert.h116
-rw-r--r--src/lib/cert/cvc/cvc_gen_cert.h180
-rw-r--r--src/lib/cert/cvc/cvc_req.cpp53
-rw-r--r--src/lib/cert/cvc/cvc_req.h59
-rw-r--r--src/lib/cert/cvc/cvc_self.cpp340
-rw-r--r--src/lib/cert/cvc/cvc_self.h170
-rw-r--r--src/lib/cert/cvc/eac_asn_obj.h238
-rw-r--r--src/lib/cert/cvc/eac_obj.h55
-rw-r--r--src/lib/cert/cvc/ecdsa_sig.cpp59
-rw-r--r--src/lib/cert/cvc/ecdsa_sig.h61
-rw-r--r--src/lib/cert/cvc/info.txt36
-rw-r--r--src/lib/cert/cvc/signed_obj.cpp96
-rw-r--r--src/lib/cert/cvc/signed_obj.h96
18 files changed, 2339 insertions, 0 deletions
diff --git a/src/lib/cert/cvc/asn1_eac_str.cpp b/src/lib/cert/cvc/asn1_eac_str.cpp
new file mode 100644
index 000000000..2084a9c03
--- /dev/null
+++ b/src/lib/cert/cvc/asn1_eac_str.cpp
@@ -0,0 +1,127 @@
+/*
+* Simple ASN.1 String Types
+* (C) 2007 FlexSecure GmbH
+* 2008-2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/eac_asn_obj.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/charset.h>
+#include <botan/parsing.h>
+#include <sstream>
+#include <ios>
+
+namespace Botan {
+
+/*
+* Create an ASN1_EAC_String
+*/
+ASN1_EAC_String::ASN1_EAC_String(const std::string& str, ASN1_Tag t) : tag(t)
+ {
+ iso_8859_str = Charset::transcode(str, LOCAL_CHARSET, LATIN1_CHARSET);
+
+ if(!sanity_check())
+ throw Invalid_Argument("ASN1_EAC_String contains illegal characters");
+ }
+
+/*
+* Return this string in ISO 8859-1 encoding
+*/
+std::string ASN1_EAC_String::iso_8859() const
+ {
+ return iso_8859_str;
+ }
+
+/*
+* Return this string in local encoding
+*/
+std::string ASN1_EAC_String::value() const
+ {
+ return Charset::transcode(iso_8859_str, LATIN1_CHARSET, LOCAL_CHARSET);
+ }
+
+/*
+* Return the type of this string object
+*/
+ASN1_Tag ASN1_EAC_String::tagging() const
+ {
+ return tag;
+ }
+
+/*
+* DER encode an ASN1_EAC_String
+*/
+void ASN1_EAC_String::encode_into(DER_Encoder& encoder) const
+ {
+ std::string value = iso_8859();
+ encoder.add_object(tagging(), APPLICATION, value);
+ }
+
+/*
+* Decode a BER encoded ASN1_EAC_String
+*/
+void ASN1_EAC_String::decode_from(BER_Decoder& source)
+ {
+ BER_Object obj = source.get_next_object();
+
+ if(obj.type_tag != this->tag)
+ {
+ std::stringstream ss;
+
+ ss << "ASN1_EAC_String tag mismatch, tag was "
+ << std::hex << obj.type_tag
+ << " expected "
+ << std::hex << this->tag;
+
+ throw Decoding_Error(ss.str());
+ }
+
+ Character_Set charset_is;
+ charset_is = LATIN1_CHARSET;
+
+ try
+ {
+ *this = ASN1_EAC_String(
+ Charset::transcode(ASN1::to_string(obj), charset_is, LOCAL_CHARSET),
+ obj.type_tag);
+ }
+ catch(Invalid_Argument& inv_arg)
+ {
+ throw Decoding_Error(std::string("ASN1_EAC_String decoding failed: ") +
+ inv_arg.what());
+ }
+ }
+
+// checks for compliance to the alphabet defined in TR-03110 v1.10, 2007-08-20
+// p. 43
+bool ASN1_EAC_String::sanity_check() const
+ {
+ const byte* rep = reinterpret_cast<const byte*>(iso_8859_str.data());
+ const size_t rep_len = iso_8859_str.size();
+
+ for(size_t i = 0; i != rep_len; ++i)
+ {
+ if((rep[i] < 0x20) || ((rep[i] >= 0x7F) && (rep[i] < 0xA0)))
+ return false;
+ }
+
+ return true;
+ }
+
+bool operator==(const ASN1_EAC_String& lhs, const ASN1_EAC_String& rhs)
+ {
+ return (lhs.iso_8859() == rhs.iso_8859());
+ }
+
+ASN1_Car::ASN1_Car(std::string const& str)
+ : ASN1_EAC_String(str, ASN1_Tag(2))
+ {}
+
+ASN1_Chr::ASN1_Chr(std::string const& str)
+ : ASN1_EAC_String(str, ASN1_Tag(32))
+ {}
+
+}
diff --git a/src/lib/cert/cvc/asn1_eac_tm.cpp b/src/lib/cert/cvc/asn1_eac_tm.cpp
new file mode 100644
index 000000000..e40f555b3
--- /dev/null
+++ b/src/lib/cert/cvc/asn1_eac_tm.cpp
@@ -0,0 +1,293 @@
+/*
+* EAC Time Types
+* (C) 2007 FlexSecure GmbH
+* 2008-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/eac_asn_obj.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/charset.h>
+#include <botan/parsing.h>
+#include <botan/internal/rounding.h>
+#include <botan/calendar.h>
+
+namespace Botan {
+
+namespace {
+
+std::vector<byte> enc_two_digit(u32bit in)
+ {
+ std::vector<byte> result;
+ in %= 100;
+ if(in < 10)
+ result.push_back(0x00);
+ else
+ {
+ u32bit y_first_pos = round_down<u32bit>(in, 10) / 10;
+ result.push_back(static_cast<byte>(y_first_pos));
+ }
+
+ u32bit y_sec_pos = in % 10;
+ result.push_back(static_cast<byte>(y_sec_pos));
+ return result;
+ }
+
+u32bit dec_two_digit(byte b1, byte b2)
+ {
+ u32bit upper = b1;
+ u32bit lower = b2;
+
+ if(upper > 9 || lower > 9)
+ throw Invalid_Argument("CVC dec_two_digit value too large");
+
+ return upper*10 + lower;
+ }
+
+}
+
+/*
+* Create an EAC_Time
+*/
+EAC_Time::EAC_Time(const std::chrono::system_clock::time_point& time,
+ ASN1_Tag t) : tag(t)
+ {
+ calendar_point cal = calendar_value(time);
+
+ year = cal.year;
+ month = cal.month;
+ day = cal.day;
+ }
+
+/*
+* Create an EAC_Time
+*/
+EAC_Time::EAC_Time(const std::string& t_spec, ASN1_Tag t) : tag(t)
+ {
+ set_to(t_spec);
+ }
+
+/*
+* Create an EAC_Time
+*/
+EAC_Time::EAC_Time(u32bit y, u32bit m, u32bit d, ASN1_Tag t) :
+ year(y), month(m), day(d), tag(t)
+ {
+ }
+
+/*
+* Set the time with a human readable string
+*/
+void EAC_Time::set_to(const std::string& time_str)
+ {
+ if(time_str == "")
+ {
+ year = month = day = 0;
+ return;
+ }
+
+ std::vector<std::string> params;
+ std::string current;
+
+ for(u32bit j = 0; j != time_str.size(); ++j)
+ {
+ if(Charset::is_digit(time_str[j]))
+ current += time_str[j];
+ else
+ {
+ if(current != "")
+ params.push_back(current);
+ current.clear();
+ }
+ }
+ if(current != "")
+ params.push_back(current);
+
+ if(params.size() != 3)
+ throw Invalid_Argument("Invalid time specification " + time_str);
+
+ year = to_u32bit(params[0]);
+ month = to_u32bit(params[1]);
+ day = to_u32bit(params[2]);
+
+ if(!passes_sanity_check())
+ throw Invalid_Argument("Invalid time specification " + time_str);
+ }
+
+
+/*
+* DER encode a EAC_Time
+*/
+void EAC_Time::encode_into(DER_Encoder& der) const
+ {
+ der.add_object(tag, APPLICATION,
+ encoded_eac_time());
+ }
+
+/*
+* Return a string representation of the time
+*/
+std::string EAC_Time::as_string() const
+ {
+ if(time_is_set() == false)
+ throw Invalid_State("EAC_Time::as_string: No time set");
+
+ return std::to_string(year * 10000 + month * 100 + day);
+ }
+
+/*
+* Return if the time has been set somehow
+*/
+bool EAC_Time::time_is_set() const
+ {
+ return (year != 0);
+ }
+
+/*
+* Return a human readable string representation
+*/
+std::string EAC_Time::readable_string() const
+ {
+ if(time_is_set() == false)
+ throw Invalid_State("EAC_Time::readable_string: No time set");
+
+ std::string output(11, 0);
+
+ std::sprintf(&output[0], "%04d/%02d/%02d", year, month, day);
+
+ return output;
+ }
+
+/*
+* Do a general sanity check on the time
+*/
+bool EAC_Time::passes_sanity_check() const
+ {
+ if(year < 2000 || year > 2099)
+ return false;
+ if(month == 0 || month > 12)
+ return false;
+ if(day == 0 || day > 31)
+ return false;
+
+ return true;
+ }
+
+/*
+* modification functions
+*/
+void EAC_Time::add_years(u32bit years)
+ {
+ year += years;
+ }
+
+void EAC_Time::add_months(u32bit months)
+ {
+ year += months/12;
+ month += months % 12;
+ if(month > 12)
+ {
+ year += 1;
+ month -= 12;
+ }
+ }
+
+/*
+* Compare this time against another
+*/
+s32bit EAC_Time::cmp(const EAC_Time& other) const
+ {
+ if(time_is_set() == false)
+ throw Invalid_State("EAC_Time::cmp: No time set");
+
+ const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0;
+
+ if(year < other.year) return EARLIER;
+ if(year > other.year) return LATER;
+ if(month < other.month) return EARLIER;
+ if(month > other.month) return LATER;
+ if(day < other.day) return EARLIER;
+ if(day > other.day) return LATER;
+
+ return SAME_TIME;
+ }
+
+/*
+* Compare two EAC_Times for in various ways
+*/
+bool operator==(const EAC_Time& t1, const EAC_Time& t2)
+ {
+ return (t1.cmp(t2) == 0);
+ }
+
+bool operator!=(const EAC_Time& t1, const EAC_Time& t2)
+ {
+ return (t1.cmp(t2) != 0);
+ }
+
+bool operator<=(const EAC_Time& t1, const EAC_Time& t2)
+ {
+ return (t1.cmp(t2) <= 0);
+ }
+
+bool operator>=(const EAC_Time& t1, const EAC_Time& t2)
+ {
+ return (t1.cmp(t2) >= 0);
+ }
+
+bool operator>(const EAC_Time& t1, const EAC_Time& t2)
+ {
+ return (t1.cmp(t2) > 0);
+ }
+
+bool operator<(const EAC_Time& t1, const EAC_Time& t2)
+ {
+ return (t1.cmp(t2) < 0);
+ }
+
+/*
+* Decode a BER encoded EAC_Time
+*/
+void EAC_Time::decode_from(BER_Decoder& source)
+ {
+ BER_Object obj = source.get_next_object();
+
+ if(obj.type_tag != this->tag)
+ throw BER_Decoding_Error("Tag mismatch when decoding");
+
+ if(obj.value.size() != 6)
+ {
+ throw Decoding_Error("EAC_Time decoding failed");
+ }
+
+ try
+ {
+ u32bit tmp_year = dec_two_digit(obj.value[0], obj.value[1]);
+ u32bit tmp_mon = dec_two_digit(obj.value[2], obj.value[3]);
+ u32bit tmp_day = dec_two_digit(obj.value[4], obj.value[5]);
+ year = tmp_year + 2000;
+ month = tmp_mon;
+ day = tmp_day;
+ }
+ catch (Invalid_Argument)
+ {
+ throw Decoding_Error("EAC_Time decoding failed");
+ }
+
+ }
+
+/*
+* make the value an octet string for encoding
+*/
+std::vector<byte> EAC_Time::encoded_eac_time() const
+ {
+ std::vector<byte> result;
+ result += enc_two_digit(year);
+ result += enc_two_digit(month);
+ result += enc_two_digit(day);
+ return result;
+ }
+
+}
diff --git a/src/lib/cert/cvc/cvc_ado.cpp b/src/lib/cert/cvc/cvc_ado.cpp
new file mode 100644
index 000000000..54bc9facd
--- /dev/null
+++ b/src/lib/cert/cvc/cvc_ado.cpp
@@ -0,0 +1,127 @@
+/*
+* CVC Certificate Constructor
+* (C) 2007 FlexSecure GmbH
+* 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/cvc_ado.h>
+#include <fstream>
+
+namespace Botan {
+
+EAC1_1_ADO::EAC1_1_ADO(DataSource& in)
+ {
+ init(in);
+ do_decode();
+ }
+
+EAC1_1_ADO::EAC1_1_ADO(const std::string& in)
+ {
+ DataSource_Stream stream(in, true);
+ init(stream);
+ do_decode();
+ }
+
+void EAC1_1_ADO::force_decode()
+ {
+ std::vector<byte> inner_cert;
+ BER_Decoder(tbs_bits)
+ .start_cons(ASN1_Tag(33))
+ .raw_bytes(inner_cert)
+ .end_cons()
+ .decode(m_car)
+ .verify_end();
+
+ std::vector<byte> req_bits = DER_Encoder()
+ .start_cons(ASN1_Tag(33), APPLICATION)
+ .raw_bytes(inner_cert)
+ .end_cons()
+ .get_contents_unlocked();
+
+ DataSource_Memory req_source(req_bits);
+ m_req = EAC1_1_Req(req_source);
+ sig_algo = m_req.sig_algo;
+ }
+
+std::vector<byte> EAC1_1_ADO::make_signed(PK_Signer& signer,
+ const std::vector<byte>& tbs_bits,
+ RandomNumberGenerator& rng)
+ {
+ const std::vector<byte> concat_sig = signer.sign_message(tbs_bits, rng);
+
+ return DER_Encoder()
+ .start_cons(ASN1_Tag(7), APPLICATION)
+ .raw_bytes(tbs_bits)
+ .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
+ .end_cons()
+ .get_contents_unlocked();
+ }
+
+ASN1_Car EAC1_1_ADO::get_car() const
+ {
+ return m_car;
+ }
+
+void EAC1_1_ADO::decode_info(DataSource& source,
+ std::vector<byte> & res_tbs_bits,
+ ECDSA_Signature & res_sig)
+ {
+ std::vector<byte> concat_sig;
+ std::vector<byte> cert_inner_bits;
+ ASN1_Car car;
+
+ BER_Decoder(source)
+ .start_cons(ASN1_Tag(7))
+ .start_cons(ASN1_Tag(33))
+ .raw_bytes(cert_inner_bits)
+ .end_cons()
+ .decode(car)
+ .decode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
+ .end_cons();
+
+ std::vector<byte> enc_cert = DER_Encoder()
+ .start_cons(ASN1_Tag(33), APPLICATION)
+ .raw_bytes(cert_inner_bits)
+ .end_cons()
+ .get_contents_unlocked();
+
+ res_tbs_bits = enc_cert;
+ res_tbs_bits += DER_Encoder().encode(car).get_contents();
+ res_sig = decode_concatenation(concat_sig);
+ }
+
+void EAC1_1_ADO::encode(Pipe& out, X509_Encoding encoding) const
+ {
+ if(encoding == PEM)
+ throw Invalid_Argument("EAC1_1_ADO::encode() cannot PEM encode an EAC object");
+
+ auto concat_sig = EAC1_1_obj<EAC1_1_ADO>::m_sig.get_concatenation();
+
+ out.write(DER_Encoder()
+ .start_cons(ASN1_Tag(7), APPLICATION)
+ .raw_bytes(tbs_bits)
+ .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
+ .end_cons()
+ .get_contents());
+ }
+
+std::vector<byte> EAC1_1_ADO::tbs_data() const
+ {
+ return tbs_bits;
+ }
+
+bool EAC1_1_ADO::operator==(EAC1_1_ADO const& rhs) const
+ {
+ return (this->get_concat_sig() == rhs.get_concat_sig()
+ && this->tbs_data() == rhs.tbs_data()
+ && this->get_car() == rhs.get_car());
+ }
+
+EAC1_1_Req EAC1_1_ADO::get_request() const
+ {
+ return m_req;
+ }
+
+}
diff --git a/src/lib/cert/cvc/cvc_ado.h b/src/lib/cert/cvc/cvc_ado.h
new file mode 100644
index 000000000..6f5b1d527
--- /dev/null
+++ b/src/lib/cert/cvc/cvc_ado.h
@@ -0,0 +1,98 @@
+/*
+* EAC1_1 CVC ADO
+* (C) 2008 Falko Strenzke
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_EAC_CVC_ADO_H__
+#define BOTAN_EAC_CVC_ADO_H__
+
+#include <botan/eac_obj.h>
+#include <botan/eac_asn_obj.h>
+#include <botan/cvc_req.h>
+#include <string>
+
+namespace Botan {
+
+/**
+* This class represents a TR03110 (EAC) v1.1 CVC ADO request
+*/
+
+ // CRTP continuation from EAC1_1_obj
+class BOTAN_DLL EAC1_1_ADO : public EAC1_1_obj<EAC1_1_ADO>
+ {
+ public:
+ friend class EAC1_1_obj<EAC1_1_ADO>;
+
+ /**
+ * Construct a CVC ADO request from a DER encoded CVC ADO request file.
+ * @param str the path to the DER encoded file
+ */
+ EAC1_1_ADO(const std::string& str);
+
+ /**
+ * Construct a CVC ADO request from a data source
+ * @param source the data source
+ */
+ EAC1_1_ADO(DataSource& source);
+
+ /**
+ * Create a signed CVC ADO request from to be signed (TBS) data
+ * @param signer the signer used to sign the CVC ADO request
+ * @param tbs_bits the TBS data to sign
+ * @param rng a random number generator
+ */
+ static std::vector<byte> make_signed(
+ PK_Signer& signer,
+ const std::vector<byte>& tbs_bits,
+ RandomNumberGenerator& rng);
+
+ /**
+ * Get the CAR of this CVC ADO request
+ * @result the CAR of this CVC ADO request
+ */
+ ASN1_Car get_car() const;
+
+ /**
+ * Get the CVC request contained in this object.
+ * @result the CVC request inside this CVC ADO request
+ */
+ EAC1_1_Req get_request() const;
+
+ /**
+ * Encode this object into a pipe. Only DER is supported.
+ * @param out the pipe to encode this object into
+ * @param encoding the encoding type to use, must be DER
+ */
+ void encode(Pipe& out, X509_Encoding encoding) const;
+
+ bool operator==(EAC1_1_ADO const& rhs) const;
+
+ /**
+ * Get the TBS data of this CVC ADO request.
+ * @result the TBS data
+ */
+ std::vector<byte> tbs_data() const;
+
+ virtual ~EAC1_1_ADO() {}
+ private:
+ ASN1_Car m_car;
+ EAC1_1_Req m_req;
+
+ void force_decode();
+ static void decode_info(DataSource& source,
+ std::vector<byte> & res_tbs_bits,
+ ECDSA_Signature & res_sig);
+ };
+
+inline bool operator!=(EAC1_1_ADO const& lhs, EAC1_1_ADO const& rhs)
+ {
+ return (!(lhs == rhs));
+ }
+
+}
+
+#endif
+
+
diff --git a/src/lib/cert/cvc/cvc_cert.cpp b/src/lib/cert/cvc/cvc_cert.cpp
new file mode 100644
index 000000000..3ab78b7d4
--- /dev/null
+++ b/src/lib/cert/cvc/cvc_cert.cpp
@@ -0,0 +1,135 @@
+/*
+ (C) 2007 FlexSecure GmbH
+ 2008-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/cvc_cert.h>
+#include <botan/oids.h>
+
+namespace Botan {
+
+ASN1_Car EAC1_1_CVC::get_car() const
+ {
+ return m_car;
+ }
+
+ASN1_Ced EAC1_1_CVC::get_ced() const
+ {
+ return m_ced;
+ }
+ASN1_Cex EAC1_1_CVC::get_cex() const
+ {
+ return m_cex;
+ }
+u32bit EAC1_1_CVC::get_chat_value() const
+ {
+ return m_chat_val;
+ }
+
+/*
+* Decode the TBSCertificate data
+*/
+void EAC1_1_CVC::force_decode()
+ {
+ std::vector<byte> enc_pk;
+ std::vector<byte> enc_chat_val;
+ size_t cpi;
+ BER_Decoder tbs_cert(tbs_bits);
+ tbs_cert.decode(cpi, ASN1_Tag(41), APPLICATION)
+ .decode(m_car)
+ .start_cons(ASN1_Tag(73))
+ .raw_bytes(enc_pk)
+ .end_cons()
+ .decode(m_chr)
+ .start_cons(ASN1_Tag(76))
+ .decode(m_chat_oid)
+ .decode(enc_chat_val, OCTET_STRING, ASN1_Tag(19), APPLICATION)
+ .end_cons()
+ .decode(m_ced)
+ .decode(m_cex)
+ .verify_end();
+
+ if(enc_chat_val.size() != 1)
+ throw Decoding_Error("CertificateHolderAuthorizationValue was not of length 1");
+
+ if(cpi != 0)
+ throw Decoding_Error("EAC1_1 certificate's cpi was not 0");
+
+ m_pk = decode_eac1_1_key(enc_pk, sig_algo);
+
+ m_chat_val = enc_chat_val[0];
+
+ self_signed = (m_car.iso_8859() == m_chr.iso_8859());
+ }
+
+/*
+* CVC Certificate Constructor
+*/
+EAC1_1_CVC::EAC1_1_CVC(DataSource& in)
+ {
+ init(in);
+ self_signed = false;
+ do_decode();
+ }
+
+EAC1_1_CVC::EAC1_1_CVC(const std::string& in)
+ {
+ DataSource_Stream stream(in, true);
+ init(stream);
+ self_signed = false;
+ do_decode();
+ }
+
+bool EAC1_1_CVC::operator==(EAC1_1_CVC const& rhs) const
+ {
+ return (tbs_data() == rhs.tbs_data()
+ && get_concat_sig() == rhs.get_concat_sig());
+ }
+
+ECDSA_PublicKey* decode_eac1_1_key(const std::vector<byte>&,
+ AlgorithmIdentifier&)
+ {
+ throw Internal_Error("decode_eac1_1_key: Unimplemented");
+ return 0;
+ }
+
+EAC1_1_CVC make_cvc_cert(PK_Signer& signer,
+ const std::vector<byte>& public_key,
+ ASN1_Car const& car,
+ ASN1_Chr const& chr,
+ byte holder_auth_templ,
+ ASN1_Ced ced,
+ ASN1_Cex cex,
+ RandomNumberGenerator& rng)
+ {
+ OID chat_oid(OIDS::lookup("CertificateHolderAuthorizationTemplate"));
+ std::vector<byte> enc_chat_val;
+ enc_chat_val.push_back(holder_auth_templ);
+
+ std::vector<byte> enc_cpi;
+ enc_cpi.push_back(0x00);
+ std::vector<byte> tbs = DER_Encoder()
+ .encode(enc_cpi, OCTET_STRING, ASN1_Tag(41), APPLICATION) // cpi
+ .encode(car)
+ .raw_bytes(public_key)
+ .encode(chr)
+ .start_cons(ASN1_Tag(76), APPLICATION)
+ .encode(chat_oid)
+ .encode(enc_chat_val, OCTET_STRING, ASN1_Tag(19), APPLICATION)
+ .end_cons()
+ .encode(ced)
+ .encode(cex)
+ .get_contents_unlocked();
+
+ std::vector<byte> signed_cert =
+ EAC1_1_CVC::make_signed(signer,
+ EAC1_1_CVC::build_cert_body(tbs),
+ rng);
+
+ DataSource_Memory source(signed_cert);
+ return EAC1_1_CVC(source);
+ }
+
+}
diff --git a/src/lib/cert/cvc/cvc_cert.h b/src/lib/cert/cvc/cvc_cert.h
new file mode 100644
index 000000000..7c084379f
--- /dev/null
+++ b/src/lib/cert/cvc/cvc_cert.h
@@ -0,0 +1,116 @@
+/*
+* EAC1_1 CVC
+* (C) 2008 Falko Strenzke
+* 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_CVC_EAC_H__
+#define BOTAN_CVC_EAC_H__
+
+#include <botan/cvc_gen_cert.h>
+#include <botan/ecdsa.h>
+#include <string>
+
+namespace Botan {
+
+/**
+* This class represents TR03110 (EAC) v1.1 CV Certificates
+*/
+class BOTAN_DLL EAC1_1_CVC : public EAC1_1_gen_CVC<EAC1_1_CVC>//Signed_Object
+ {
+ public:
+ friend class EAC1_1_obj<EAC1_1_CVC>;
+
+ /**
+ * Get the CAR of the certificate.
+ * @result the CAR of the certificate
+ */
+ ASN1_Car get_car() const;
+
+ /**
+ * Get the CED of this certificate.
+ * @result the CED this certificate
+ */
+ ASN1_Ced get_ced() const;
+
+ /**
+ * Get the CEX of this certificate.
+ * @result the CEX this certificate
+ */
+ ASN1_Cex get_cex() const;
+
+ /**
+ * Get the CHAT value.
+ * @result the CHAT value
+ */
+ u32bit get_chat_value() const;
+
+ bool operator==(const EAC1_1_CVC&) const;
+
+ /**
+ * Construct a CVC from a data source
+ * @param source the data source
+ */
+ EAC1_1_CVC(DataSource& source);
+
+ /**
+ * Construct a CVC from a file
+ * @param str the path to the certificate file
+ */
+ EAC1_1_CVC(const std::string& str);
+
+ virtual ~EAC1_1_CVC() {}
+ private:
+ void force_decode();
+ EAC1_1_CVC() {}
+
+ ASN1_Car m_car;
+ ASN1_Ced m_ced;
+ ASN1_Cex m_cex;
+ byte m_chat_val;
+ OID m_chat_oid;
+ };
+
+/*
+* Comparison
+*/
+inline bool operator!=(EAC1_1_CVC const& lhs, EAC1_1_CVC const& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+/**
+* Create an arbitrary EAC 1.1 CVC.
+* The desired key encoding must be set within the key (if applicable).
+* @param signer the signer used to sign the certificate
+* @param public_key the DER encoded public key to appear in
+* the certificate
+* @param car the CAR of the certificate
+* @param chr the CHR of the certificate
+* @param holder_auth_templ the holder authorization value byte to
+* appear in the CHAT of the certificate
+* @param ced the CED to appear in the certificate
+* @param cex the CEX to appear in the certificate
+* @param rng a random number generator
+*/
+EAC1_1_CVC BOTAN_DLL make_cvc_cert(PK_Signer& signer,
+ const std::vector<byte>& public_key,
+ ASN1_Car const& car,
+ ASN1_Chr const& chr,
+ byte holder_auth_templ,
+ ASN1_Ced ced,
+ ASN1_Cex cex,
+ RandomNumberGenerator& rng);
+
+/**
+* Decode an EAC encoding ECDSA key
+*/
+BOTAN_DLL ECDSA_PublicKey* decode_eac1_1_key(const std::vector<byte>& enc_key,
+ AlgorithmIdentifier& sig_algo);
+
+}
+
+#endif
+
diff --git a/src/lib/cert/cvc/cvc_gen_cert.h b/src/lib/cert/cvc/cvc_gen_cert.h
new file mode 100644
index 000000000..7fa4eba29
--- /dev/null
+++ b/src/lib/cert/cvc/cvc_gen_cert.h
@@ -0,0 +1,180 @@
+/*
+* EAC1_1 general CVC
+* (C) 2008 Falko Strenzke
+* 2008-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_EAC_CVC_GEN_CERT_H__
+#define BOTAN_EAC_CVC_GEN_CERT_H__
+
+#include <botan/eac_obj.h>
+#include <botan/eac_asn_obj.h>
+#include <botan/ecdsa.h>
+#include <botan/pubkey.h>
+
+namespace Botan {
+
+/**
+* This class represents TR03110 (EAC) v1.1 generalized CV Certificates
+*/
+template<typename Derived>
+class EAC1_1_gen_CVC : public EAC1_1_obj<Derived> // CRTP continuation from EAC1_1_obj
+ {
+ friend class EAC1_1_obj<EAC1_1_gen_CVC>;
+
+ public:
+
+ /**
+ * Get this certificates public key.
+ * @result this certificates public key
+ */
+ Public_Key* subject_public_key() const;
+
+ /**
+ * Find out whether this object is self signed.
+ * @result true if this object is self signed
+ */
+ bool is_self_signed() const;
+
+ /**
+ * Get the CHR of the certificate.
+ * @result the CHR of the certificate
+ */
+ ASN1_Chr get_chr() const;
+
+ /**
+ * Put the DER encoded version of this object into a pipe. PEM
+ * is not supported.
+ * @param out the pipe to push the DER encoded version into
+ * @param encoding the encoding to use. Must be DER.
+ */
+ void encode(Pipe& out, X509_Encoding encoding) const;
+
+ /**
+ * Get the to-be-signed (TBS) data of this object.
+ * @result the TBS data of this object
+ */
+ std::vector<byte> tbs_data() const;
+
+ /**
+ * Build the DER encoded certifcate body of an object
+ * @param tbs the data to be signed
+ * @result the correctly encoded body of the object
+ */
+ static std::vector<byte> build_cert_body(const std::vector<byte>& tbs);
+
+ /**
+ * Create a signed generalized CVC object.
+ * @param signer the signer used to sign this object
+ * @param tbs_bits the body the generalized CVC object to be signed
+ * @param rng a random number generator
+ * @result the DER encoded signed generalized CVC object
+ */
+ static std::vector<byte> make_signed(
+ PK_Signer& signer,
+ const std::vector<byte>& tbs_bits,
+ RandomNumberGenerator& rng);
+
+ EAC1_1_gen_CVC() { m_pk = 0; }
+
+ virtual ~EAC1_1_gen_CVC<Derived>()
+ { delete m_pk; }
+
+ protected:
+ ECDSA_PublicKey* m_pk;
+ ASN1_Chr m_chr;
+ bool self_signed;
+
+ static void decode_info(DataSource& source,
+ std::vector<byte> & res_tbs_bits,
+ ECDSA_Signature & res_sig);
+
+ };
+
+template<typename Derived> ASN1_Chr EAC1_1_gen_CVC<Derived>::get_chr() const
+ {
+ return m_chr;
+ }
+
+template<typename Derived> bool EAC1_1_gen_CVC<Derived>::is_self_signed() const
+ {
+ return self_signed;
+ }
+
+template<typename Derived>
+std::vector<byte> EAC1_1_gen_CVC<Derived>::make_signed(
+ PK_Signer& signer,
+ const std::vector<byte>& tbs_bits,
+ RandomNumberGenerator& rng) // static
+ {
+ const auto concat_sig = signer.sign_message(tbs_bits, rng);
+
+ return DER_Encoder()
+ .start_cons(ASN1_Tag(33), APPLICATION)
+ .raw_bytes(tbs_bits)
+ .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
+ .end_cons()
+ .get_contents_unlocked();
+ }
+
+template<typename Derived>
+Public_Key* EAC1_1_gen_CVC<Derived>::subject_public_key() const
+ {
+ return new ECDSA_PublicKey(*m_pk);
+ }
+
+template<typename Derived> std::vector<byte> EAC1_1_gen_CVC<Derived>::build_cert_body(const std::vector<byte>& tbs)
+ {
+ return DER_Encoder()
+ .start_cons(ASN1_Tag(78), APPLICATION)
+ .raw_bytes(tbs)
+ .end_cons().get_contents_unlocked();
+ }
+
+template<typename Derived> std::vector<byte> EAC1_1_gen_CVC<Derived>::tbs_data() const
+ {
+ return build_cert_body(EAC1_1_obj<Derived>::tbs_bits);
+ }
+
+template<typename Derived> void EAC1_1_gen_CVC<Derived>::encode(Pipe& out, X509_Encoding encoding) const
+ {
+ std::vector<byte> concat_sig(EAC1_1_obj<Derived>::m_sig.get_concatenation());
+ std::vector<byte> der = DER_Encoder()
+ .start_cons(ASN1_Tag(33), APPLICATION)
+ .start_cons(ASN1_Tag(78), APPLICATION)
+ .raw_bytes(EAC1_1_obj<Derived>::tbs_bits)
+ .end_cons()
+ .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
+ .end_cons()
+ .get_contents_unlocked();
+
+ if (encoding == PEM)
+ throw Invalid_Argument("EAC1_1_gen_CVC::encode() cannot PEM encode an EAC object");
+ else
+ out.write(der);
+ }
+
+template<typename Derived>
+void EAC1_1_gen_CVC<Derived>::decode_info(
+ DataSource& source,
+ std::vector<byte> & res_tbs_bits,
+ ECDSA_Signature & res_sig)
+ {
+ std::vector<byte> concat_sig;
+ BER_Decoder(source)
+ .start_cons(ASN1_Tag(33))
+ .start_cons(ASN1_Tag(78))
+ .raw_bytes(res_tbs_bits)
+ .end_cons()
+ .decode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
+ .end_cons();
+ res_sig = decode_concatenation(concat_sig);
+ }
+
+}
+
+#endif
+
+
diff --git a/src/lib/cert/cvc/cvc_req.cpp b/src/lib/cert/cvc/cvc_req.cpp
new file mode 100644
index 000000000..6c013f755
--- /dev/null
+++ b/src/lib/cert/cvc/cvc_req.cpp
@@ -0,0 +1,53 @@
+/*
+ (C) 2007 FlexSecure GmbH
+ 2008-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/cvc_req.h>
+#include <botan/cvc_cert.h>
+#include <botan/ber_dec.h>
+
+namespace Botan {
+
+bool EAC1_1_Req::operator==(EAC1_1_Req const& rhs) const
+ {
+ return (this->tbs_data() == rhs.tbs_data() &&
+ this->get_concat_sig() == rhs.get_concat_sig());
+ }
+
+void EAC1_1_Req::force_decode()
+ {
+ std::vector<byte> enc_pk;
+ BER_Decoder tbs_cert(tbs_bits);
+ size_t cpi;
+ tbs_cert.decode(cpi, ASN1_Tag(41), APPLICATION)
+ .start_cons(ASN1_Tag(73))
+ .raw_bytes(enc_pk)
+ .end_cons()
+ .decode(m_chr)
+ .verify_end();
+
+ if(cpi != 0)
+ throw Decoding_Error("EAC1_1 requests cpi was not 0");
+
+ m_pk = decode_eac1_1_key(enc_pk, sig_algo);
+ }
+
+EAC1_1_Req::EAC1_1_Req(DataSource& in)
+ {
+ init(in);
+ self_signed = true;
+ do_decode();
+ }
+
+EAC1_1_Req::EAC1_1_Req(const std::string& in)
+ {
+ DataSource_Stream stream(in, true);
+ init(stream);
+ self_signed = true;
+ do_decode();
+ }
+
+}
diff --git a/src/lib/cert/cvc/cvc_req.h b/src/lib/cert/cvc/cvc_req.h
new file mode 100644
index 000000000..ac4e22453
--- /dev/null
+++ b/src/lib/cert/cvc/cvc_req.h
@@ -0,0 +1,59 @@
+/*
+* EAC1_1 CVC Request
+* (C) 2008 Falko Strenzke
+* 2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_EAC_CVC_REQ_H__
+#define BOTAN_EAC_CVC_REQ_H__
+
+#include <botan/cvc_gen_cert.h>
+
+namespace Botan {
+
+/**
+* This class represents TR03110 v1.1 EAC CV Certificate Requests.
+*/
+class BOTAN_DLL EAC1_1_Req : public EAC1_1_gen_CVC<EAC1_1_Req>
+ {
+ public:
+ friend class EAC1_1_ADO;
+ friend class EAC1_1_obj<EAC1_1_Req>;
+
+ /**
+ * Compare for equality with other
+ * @param other compare for equality with this object
+ */
+ bool operator==(const EAC1_1_Req& other) const;
+
+ /**
+ * Construct a CVC request from a data source.
+ * @param source the data source
+ */
+ EAC1_1_Req(DataSource& source);
+
+ /**
+ * Construct a CVC request from a DER encoded CVC request file.
+ * @param str the path to the DER encoded file
+ */
+ EAC1_1_Req(const std::string& str);
+
+ virtual ~EAC1_1_Req(){}
+ private:
+ void force_decode();
+ EAC1_1_Req() {}
+ };
+
+/*
+* Comparison Operator
+*/
+inline bool operator!=(EAC1_1_Req const& lhs, EAC1_1_Req const& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+}
+
+#endif
diff --git a/src/lib/cert/cvc/cvc_self.cpp b/src/lib/cert/cvc/cvc_self.cpp
new file mode 100644
index 000000000..46e4960e1
--- /dev/null
+++ b/src/lib/cert/cvc/cvc_self.cpp
@@ -0,0 +1,340 @@
+/*
+ (C) 2007 FlexSecure GmbH
+ 2008-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/cvc_self.h>
+#include <botan/ecc_key.h>
+#include <botan/point_gfp.h>
+#include <botan/oids.h>
+#include <sstream>
+#include <memory>
+
+namespace Botan {
+
+namespace {
+
+/*
+* cvc CHAT values
+*/
+enum CHAT_values{
+ CVCA = 0xC0,
+ DVCA_domestic = 0x80,
+ DVCA_foreign = 0x40,
+ IS = 0x00,
+
+ IRIS = 0x02,
+ FINGERPRINT = 0x01
+};
+
+void encode_eac_bigint(DER_Encoder& der, const BigInt& x, ASN1_Tag tag)
+ {
+ der.encode(BigInt::encode_1363(x, x.bytes()), OCTET_STRING, tag);
+ }
+
+std::vector<byte> eac_1_1_encoding(const EC_PublicKey* key,
+ const OID& sig_algo)
+ {
+ if(key->domain_format() == EC_DOMPAR_ENC_OID)
+ throw Encoding_Error("CVC encoder: cannot encode parameters by OID");
+
+ const EC_Group& domain = key->domain();
+
+ // This is why we can't have nice things
+
+ DER_Encoder enc;
+ enc.start_cons(ASN1_Tag(73), APPLICATION)
+ .encode(sig_algo);
+
+ if(key->domain_format() == EC_DOMPAR_ENC_EXPLICIT)
+ {
+ encode_eac_bigint(enc, domain.get_curve().get_p(), ASN1_Tag(1));
+ encode_eac_bigint(enc, domain.get_curve().get_a(), ASN1_Tag(2));
+ encode_eac_bigint(enc, domain.get_curve().get_b(), ASN1_Tag(3));
+
+ enc.encode(EC2OSP(domain.get_base_point(), PointGFp::UNCOMPRESSED),
+ OCTET_STRING, ASN1_Tag(4));
+
+ encode_eac_bigint(enc, domain.get_order(), ASN1_Tag(4));
+ }
+
+ enc.encode(EC2OSP(key->public_point(), PointGFp::UNCOMPRESSED),
+ OCTET_STRING, ASN1_Tag(6));
+
+ if(key->domain_format() == EC_DOMPAR_ENC_EXPLICIT)
+ encode_eac_bigint(enc, domain.get_cofactor(), ASN1_Tag(7));
+
+ enc.end_cons();
+
+ return enc.get_contents_unlocked();
+ }
+
+std::string padding_and_hash_from_oid(OID const& oid)
+ {
+ std::string padding_and_hash = OIDS::lookup(oid); // use the hash
+
+ if(padding_and_hash.substr(0,6) != "ECDSA/")
+ throw Invalid_State("CVC: Can only use ECDSA, not " + padding_and_hash);
+
+ padding_and_hash.erase(0, padding_and_hash.find("/") + 1);
+ return padding_and_hash;
+ }
+
+}
+
+namespace CVC_EAC {
+
+EAC1_1_CVC create_self_signed_cert(Private_Key const& key,
+ EAC1_1_CVC_Options const& opt,
+ RandomNumberGenerator& rng)
+ {
+ // NOTE: we ignore the value of opt.chr
+
+ const ECDSA_PrivateKey* priv_key = dynamic_cast<const ECDSA_PrivateKey*>(&key);
+
+ if(priv_key == 0)
+ throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
+
+ ASN1_Chr chr(opt.car.value());
+
+ AlgorithmIdentifier sig_algo;
+ std::string padding_and_hash("EMSA1_BSI(" + opt.hash_alg + ")");
+ sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash);
+ sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM);
+
+ PK_Signer signer(*priv_key, padding_and_hash);
+
+ std::vector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
+
+ return make_cvc_cert(signer,
+ enc_public_key,
+ opt.car, chr,
+ opt.holder_auth_templ,
+ opt.ced, opt.cex, rng);
+ }
+
+EAC1_1_Req create_cvc_req(Private_Key const& key,
+ ASN1_Chr const& chr,
+ std::string const& hash_alg,
+ RandomNumberGenerator& rng)
+ {
+
+ ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
+ if (priv_key == 0)
+ {
+ throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
+ }
+ AlgorithmIdentifier sig_algo;
+ std::string padding_and_hash("EMSA1_BSI(" + hash_alg + ")");
+ sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash);
+ sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM);
+
+ PK_Signer signer(*priv_key, padding_and_hash);
+
+ std::vector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
+
+ std::vector<byte> enc_cpi;
+ enc_cpi.push_back(0x00);
+ std::vector<byte> tbs = DER_Encoder()
+ .encode(enc_cpi, OCTET_STRING, ASN1_Tag(41), APPLICATION)
+ .raw_bytes(enc_public_key)
+ .encode(chr)
+ .get_contents_unlocked();
+
+ std::vector<byte> signed_cert =
+ EAC1_1_gen_CVC<EAC1_1_Req>::make_signed(signer,
+ EAC1_1_gen_CVC<EAC1_1_Req>::build_cert_body(tbs),
+ rng);
+
+ DataSource_Memory source(signed_cert);
+ return EAC1_1_Req(source);
+ }
+
+EAC1_1_ADO create_ado_req(Private_Key const& key,
+ EAC1_1_Req const& req,
+ ASN1_Car const& car,
+ RandomNumberGenerator& rng)
+ {
+
+ ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
+ if (priv_key == 0)
+ {
+ throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
+ }
+
+ std::string padding_and_hash = padding_and_hash_from_oid(req.signature_algorithm().oid);
+ PK_Signer signer(*priv_key, padding_and_hash);
+ std::vector<byte> tbs_bits = req.BER_encode();
+ tbs_bits += DER_Encoder().encode(car).get_contents();
+
+ std::vector<byte> signed_cert =
+ EAC1_1_ADO::make_signed(signer, tbs_bits, rng);
+
+ DataSource_Memory source(signed_cert);
+ return EAC1_1_ADO(source);
+ }
+
+} // namespace CVC_EAC
+namespace DE_EAC
+{
+
+EAC1_1_CVC create_cvca(Private_Key const& key,
+ std::string const& hash,
+ ASN1_Car const& car, bool iris, bool fingerpr,
+ u32bit cvca_validity_months,
+ RandomNumberGenerator& rng)
+ {
+ ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
+ if (priv_key == 0)
+ {
+ throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
+ }
+ EAC1_1_CVC_Options opts;
+ opts.car = car;
+
+ opts.ced = ASN1_Ced(std::chrono::system_clock::now());
+ opts.cex = ASN1_Cex(opts.ced);
+ opts.cex.add_months(cvca_validity_months);
+ opts.holder_auth_templ = (CVCA | (iris * IRIS) | (fingerpr * FINGERPRINT));
+ opts.hash_alg = hash;
+ return CVC_EAC::create_self_signed_cert(*priv_key, opts, rng);
+ }
+
+
+
+EAC1_1_CVC link_cvca(EAC1_1_CVC const& signer,
+ Private_Key const& key,
+ EAC1_1_CVC const& signee,
+ RandomNumberGenerator& rng)
+ {
+ const ECDSA_PrivateKey* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
+
+ if (priv_key == 0)
+ throw Invalid_Argument("link_cvca(): unsupported key type");
+
+ ASN1_Ced ced(std::chrono::system_clock::now());
+ ASN1_Cex cex(signee.get_cex());
+ if (*static_cast<EAC_Time*>(&ced) > *static_cast<EAC_Time*>(&cex))
+ {
+ std::string detail("link_cvca(): validity periods of provided certificates don't overlap: currend time = ced = ");
+ detail += ced.as_string();
+ detail += ", signee.cex = ";
+ detail += cex.as_string();
+ throw Invalid_Argument(detail);
+ }
+ if (signer.signature_algorithm() != signee.signature_algorithm())
+ {
+ throw Invalid_Argument("link_cvca(): signature algorithms of signer and signee don't match");
+ }
+ AlgorithmIdentifier sig_algo = signer.signature_algorithm();
+ std::string padding_and_hash = padding_and_hash_from_oid(sig_algo.oid);
+ PK_Signer pk_signer(*priv_key, padding_and_hash);
+ std::unique_ptr<Public_Key> pk(signee.subject_public_key());
+ ECDSA_PublicKey* subj_pk = dynamic_cast<ECDSA_PublicKey*>(pk.get());
+ subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_EXPLICIT);
+
+ std::vector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
+
+ return make_cvc_cert(pk_signer, enc_public_key,
+ signer.get_car(),
+ signee.get_chr(),
+ signer.get_chat_value(),
+ ced, cex,
+ rng);
+ }
+
+EAC1_1_CVC sign_request(EAC1_1_CVC const& signer_cert,
+ Private_Key const& key,
+ EAC1_1_Req const& signee,
+ u32bit seqnr,
+ u32bit seqnr_len,
+ bool domestic,
+ u32bit dvca_validity_months,
+ u32bit ca_is_validity_months,
+ RandomNumberGenerator& rng)
+ {
+ ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
+ if (priv_key == 0)
+ {
+ throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
+ }
+ std::string chr_str = signee.get_chr().value();
+
+ std::string seqnr_string = std::to_string(seqnr);
+
+ while(seqnr_string.size() < seqnr_len)
+ seqnr_string = '0' + seqnr_string;
+
+ chr_str += seqnr_string;
+ ASN1_Chr chr(chr_str);
+ std::string padding_and_hash = padding_and_hash_from_oid(signee.signature_algorithm().oid);
+ PK_Signer pk_signer(*priv_key, padding_and_hash);
+ std::unique_ptr<Public_Key> pk(signee.subject_public_key());
+ ECDSA_PublicKey* subj_pk = dynamic_cast<ECDSA_PublicKey*>(pk.get());
+ std::unique_ptr<Public_Key> signer_pk(signer_cert.subject_public_key());
+
+ // for the case that the domain parameters are not set...
+ // (we use those from the signer because they must fit)
+ //subj_pk->set_domain_parameters(priv_key->domain_parameters());
+
+ subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA);
+
+ AlgorithmIdentifier sig_algo(signer_cert.signature_algorithm());
+
+ ASN1_Ced ced(std::chrono::system_clock::now());
+
+ u32bit chat_val;
+ u32bit chat_low = signer_cert.get_chat_value() & 0x3; // take the chat rights from signer
+ ASN1_Cex cex(ced);
+ if ((signer_cert.get_chat_value() & CVCA) == CVCA)
+ {
+ // we sign a dvca
+ cex.add_months(dvca_validity_months);
+ if (domestic)
+ chat_val = DVCA_domestic | chat_low;
+ else
+ chat_val = DVCA_foreign | chat_low;
+ }
+ else if ((signer_cert.get_chat_value() & DVCA_domestic) == DVCA_domestic ||
+ (signer_cert.get_chat_value() & DVCA_foreign) == DVCA_foreign)
+ {
+ cex.add_months(ca_is_validity_months);
+ chat_val = IS | chat_low;
+ }
+ else
+ {
+ throw Invalid_Argument("sign_request(): encountered illegal value for CHAT");
+ // (IS cannot sign certificates)
+ }
+
+ std::vector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
+
+ return make_cvc_cert(pk_signer, enc_public_key,
+ ASN1_Car(signer_cert.get_chr().iso_8859()),
+ chr,
+ chat_val,
+ ced,
+ cex,
+ rng);
+ }
+
+EAC1_1_Req create_cvc_req(Private_Key const& prkey,
+ ASN1_Chr const& chr,
+ std::string const& hash_alg,
+ RandomNumberGenerator& rng)
+ {
+ ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&prkey);
+ if (priv_key == 0)
+ {
+ throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
+ }
+ ECDSA_PrivateKey key(*priv_key);
+ key.set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA);
+ return CVC_EAC::create_cvc_req(key, chr, hash_alg, rng);
+ }
+
+} // namespace DE_EAC
+
+}
diff --git a/src/lib/cert/cvc/cvc_self.h b/src/lib/cert/cvc/cvc_self.h
new file mode 100644
index 000000000..1e6bbe49a
--- /dev/null
+++ b/src/lib/cert/cvc/cvc_self.h
@@ -0,0 +1,170 @@
+/*
+* CVC Self-Signed Certificate
+* (C) 2007 FlexSecure GmbH
+* 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_CVC_EAC_SELF_H__
+#define BOTAN_CVC_EAC_SELF_H__
+
+#include <botan/pkcs8.h>
+#include <botan/cvc_cert.h>
+#include <botan/ecdsa.h>
+#include <botan/asn1_obj.h>
+#include <botan/cvc_req.h>
+#include <botan/cvc_ado.h>
+
+namespace Botan {
+
+/**
+* This class represents a set of options used for the creation of CVC certificates
+*/
+class BOTAN_DLL EAC1_1_CVC_Options
+ {
+ public:
+
+ ASN1_Car car;
+ ASN1_Chr chr;
+ byte holder_auth_templ;
+ ASN1_Ced ced;
+ ASN1_Cex cex;
+ std::string hash_alg;
+ };
+
+/**
+* This namespace represents general EAC 1.1 convenience functions.
+*/
+namespace CVC_EAC {
+
+/**
+* Create a selfsigned CVCA
+* @param rng the rng to use
+* @param key the ECDSA private key to be used to sign the certificate
+* @param opts used to set several parameters. Necessary are:
+* car, holder_auth_templ, hash_alg, ced, cex and hash_alg
+* @result the self signed certificate
+*/
+
+EAC1_1_CVC BOTAN_DLL create_self_signed_cert(Private_Key const& key,
+ EAC1_1_CVC_Options const& opts,
+ RandomNumberGenerator& rng);
+/**
+* Create a CVC request. The key encoding will be according to the provided private key.
+* @param priv_key the private key associated with the requesting entity
+* @param chr the chr to appear in the certificate (to be provided without
+* sequence number)
+* @param hash_alg the string defining the hash algorithm to be used for the creation
+* of the signature
+* @param rng the rng to use
+* @result the new request
+*/
+EAC1_1_Req BOTAN_DLL create_cvc_req(Private_Key const& priv_key,
+ ASN1_Chr const& chr,
+ std::string const& hash_alg,
+ RandomNumberGenerator& rng);
+
+/**
+* Create an ADO from a request object.
+* @param priv_key the private key used to sign the ADO
+* @param req the request forming the body of the ADO
+* @param car the CAR forming the body of the ADO, i.e. the
+* CHR of the entity associated with the provided private key
+* @param rng the rng to use
+*/
+EAC1_1_ADO BOTAN_DLL create_ado_req(Private_Key const& priv_key,
+ EAC1_1_Req const& req,
+ ASN1_Car const& car,
+ RandomNumberGenerator& rng);
+}
+/**
+* This namespace represents EAC 1.1 CVC convenience functions
+* following the specific german requirements.
+*/
+
+namespace DE_EAC {
+
+/**
+* Create a CVCA certificate.
+* @param priv_key the private key associated with the CVCA certificate
+* to be created
+* @param hash the string identifying the hash algorithm to be used
+* for signing the certificate to be created
+* @param car the CAR of the certificate to be created
+* @param iris indicates whether the entity associated with the certificate
+* shall be entitled to read the biometrical iris image
+* @param fingerpr indicates whether the entity associated with the certificate
+* shall be entitled to read the biometrical fingerprint image
+* @param cvca_validity_months length of time in months this will be valid
+* @param rng a random number generator
+* @result the CVCA certificate created
+*/
+EAC1_1_CVC BOTAN_DLL create_cvca(Private_Key const& priv_key,
+ std::string const& hash,
+ ASN1_Car const& car,
+ bool iris,
+ bool fingerpr,
+ u32bit cvca_validity_months,
+ RandomNumberGenerator& rng);
+
+/**
+* Create a link certificate between two CVCA certificates. The key
+* encoding will be implicitCA.
+* @param signer the cvca certificate associated with the signing
+* entity
+* @param priv_key the private key associated with the signer
+* @param to_be_signed the certificate which whose CAR/CHR will be
+* the holder of the link certificate
+* @param rng a random number generator
+*/
+EAC1_1_CVC BOTAN_DLL link_cvca(EAC1_1_CVC const& signer,
+ Private_Key const& priv_key,
+ EAC1_1_CVC const& to_be_signed,
+ RandomNumberGenerator& rng);
+
+/**
+* Create a CVC request. The key encoding will be implicitCA.
+* @param priv_key the private key associated with the requesting entity
+* @param chr the chr to appear in the certificate (to be provided without
+* sequence number)
+* @param hash_alg the string defining the hash algorithm to be used for the creation
+* of the signature
+* @param rng a random number generator
+* @result the new request
+*/
+EAC1_1_Req BOTAN_DLL create_cvc_req(Private_Key const& priv_key,
+ ASN1_Chr const& chr,
+ std::string const& hash_alg,
+ RandomNumberGenerator& rng);
+
+/**
+* Sign a CVC request.
+* @param signer_cert the certificate of the signing entity
+* @param priv_key the private key of the signing entity
+* @param req the request to be signed
+* @param seqnr the sequence number of the certificate to be created
+* @param seqnr_len the number of digits the sequence number will be
+* encoded in
+* @param domestic indicates whether to sign a domestic or a foreign
+* certificate: set to true for domestic
+* @param dvca_validity_months validity period in months
+* @param ca_is_validity_months validity period in months
+* @param rng a random number generator
+* @result the new certificate
+*
+**/
+EAC1_1_CVC BOTAN_DLL sign_request(EAC1_1_CVC const& signer_cert,
+ Private_Key const& priv_key,
+ EAC1_1_Req const& req,
+ u32bit seqnr,
+ u32bit seqnr_len,
+ bool domestic,
+ u32bit dvca_validity_months,
+ u32bit ca_is_validity_months,
+ RandomNumberGenerator& rng);
+}
+
+}
+
+#endif
diff --git a/src/lib/cert/cvc/eac_asn_obj.h b/src/lib/cert/cvc/eac_asn_obj.h
new file mode 100644
index 000000000..ab8536e45
--- /dev/null
+++ b/src/lib/cert/cvc/eac_asn_obj.h
@@ -0,0 +1,238 @@
+/*
+* EAC ASN.1 Objects
+* (C) 2007-2008 FlexSecure GmbH
+* 2008-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_EAC_ASN1_OBJ_H__
+#define BOTAN_EAC_ASN1_OBJ_H__
+
+#include <botan/asn1_obj.h>
+
+namespace Botan {
+
+/**
+* This class represents CVC EAC Time objects.
+* It only models year, month and day. Only limited sanity checks of
+* the inputted date value are performed.
+*/
+class BOTAN_DLL EAC_Time : public ASN1_Object
+ {
+ public:
+ void encode_into(class DER_Encoder&) const;
+ void decode_from(class BER_Decoder&);
+
+ /**
+ * Get a this objects value as a string.
+ * @return date string
+ */
+ std::string as_string() const;
+
+ /**
+ * Get a this objects value as a readable formatted string.
+ * @return date string
+ */
+ std::string readable_string() const;
+
+ /**
+ * Find out whether this object's values have been set.
+ * @return true if this object's internal values are set
+ */
+ bool time_is_set() const;
+
+ /**
+ * Compare this to another EAC_Time object.
+ * @return -1 if this object's date is earlier than
+ * other, +1 in the opposite case, and 0 if both dates are
+ * equal.
+ */
+ s32bit cmp(const EAC_Time& other) const;
+
+ /**
+ * Set this' value by a string value.
+ * @param str a string in the format "yyyy mm dd",
+ * e.g. "2007 08 01"
+ */
+ void set_to(const std::string& str);
+
+ /**
+ * Add the specified number of years to this.
+ * @param years the number of years to add
+ */
+ void add_years(u32bit years);
+
+ /**
+ * Add the specified number of months to this.
+ * @param months the number of months to add
+ */
+ void add_months(u32bit months);
+
+ /**
+ * Get the year value of this objects.
+ * @return year value
+ */
+ u32bit get_year() const { return year; }
+
+ /**
+ * Get the month value of this objects.
+ * @return month value
+ */
+ u32bit get_month() const { return month; }
+
+ /**
+ * Get the day value of this objects.
+ * @return day value
+ */
+ u32bit get_day() const { return day; }
+
+ EAC_Time(const std::chrono::system_clock::time_point& time,
+ ASN1_Tag tag = ASN1_Tag(0));
+
+ EAC_Time(const std::string& yyyy_mm_dd,
+ ASN1_Tag tag = ASN1_Tag(0));
+
+ EAC_Time(u32bit year, u32bit month, u32bit day,
+ ASN1_Tag tag = ASN1_Tag(0));
+
+ virtual ~EAC_Time() {}
+ private:
+ std::vector<byte> encoded_eac_time() const;
+ bool passes_sanity_check() const;
+ u32bit year, month, day;
+ ASN1_Tag tag;
+ };
+
+/**
+* This class represents CVC CEDs. Only limited sanity checks of
+* the inputted date value are performed.
+*/
+class BOTAN_DLL ASN1_Ced : public EAC_Time
+ {
+ public:
+ /**
+ * Construct a CED from a string value.
+ * @param str a string in the format "yyyy mm dd",
+ * e.g. "2007 08 01"
+ */
+ ASN1_Ced(const std::string& str = "") :
+ EAC_Time(str, ASN1_Tag(37)) {}
+
+ /**
+ * Construct a CED from a time point
+ */
+ ASN1_Ced(const std::chrono::system_clock::time_point& time) :
+ EAC_Time(time, ASN1_Tag(37)) {}
+
+ /**
+ * Copy constructor (for general EAC_Time objects).
+ * @param other the object to copy from
+ */
+ ASN1_Ced(const EAC_Time& other) :
+ EAC_Time(other.get_year(), other.get_month(), other.get_day(),
+ ASN1_Tag(37))
+ {}
+ };
+
+/**
+* This class represents CVC CEXs. Only limited sanity checks of
+* the inputted date value are performed.
+*/
+class BOTAN_DLL ASN1_Cex : public EAC_Time
+ {
+ public:
+ /**
+ * Construct a CEX from a string value.
+ * @param str a string in the format "yyyy mm dd",
+ * e.g. "2007 08 01"
+ */
+ ASN1_Cex(const std::string& str = "") :
+ EAC_Time(str, ASN1_Tag(36)) {}
+
+ ASN1_Cex(const std::chrono::system_clock::time_point& time) :
+ EAC_Time(time, ASN1_Tag(36)) {}
+
+ ASN1_Cex(const EAC_Time& other) :
+ EAC_Time(other.get_year(), other.get_month(), other.get_day(),
+ ASN1_Tag(36))
+ {}
+ };
+
+/**
+* Base class for car/chr of cv certificates.
+*/
+class BOTAN_DLL ASN1_EAC_String: public ASN1_Object
+ {
+ public:
+ void encode_into(class DER_Encoder&) const;
+ void decode_from(class BER_Decoder&);
+
+ /**
+ * Get this objects string value.
+ * @return string value
+ */
+ std::string value() const;
+
+ /**
+ * Get this objects string value.
+ * @return string value in iso8859 encoding
+ */
+ std::string iso_8859() const;
+
+ ASN1_Tag tagging() const;
+ ASN1_EAC_String(const std::string& str, ASN1_Tag the_tag);
+
+ virtual ~ASN1_EAC_String() {}
+ protected:
+ bool sanity_check() const;
+ private:
+ std::string iso_8859_str;
+ ASN1_Tag tag;
+ };
+
+/**
+* This class represents CARs of CVCs. (String tagged with 2)
+*/
+class BOTAN_DLL ASN1_Car : public ASN1_EAC_String
+ {
+ public:
+ /**
+ * Create a CAR with the specified content.
+ * @param str the CAR value
+ */
+ ASN1_Car(std::string const& str = "");
+ };
+
+/**
+* This class represents CHRs of CVCs (tag 32)
+*/
+class BOTAN_DLL ASN1_Chr : public ASN1_EAC_String
+ {
+ public:
+ /**
+ * Create a CHR with the specified content.
+ * @param str the CHR value
+ */
+ ASN1_Chr(std::string const& str = "");
+ };
+
+/*
+* Comparison Operations
+*/
+bool BOTAN_DLL operator==(const EAC_Time&, const EAC_Time&);
+bool BOTAN_DLL operator!=(const EAC_Time&, const EAC_Time&);
+bool BOTAN_DLL operator<=(const EAC_Time&, const EAC_Time&);
+bool BOTAN_DLL operator>=(const EAC_Time&, const EAC_Time&);
+bool BOTAN_DLL operator>(const EAC_Time&, const EAC_Time&);
+bool BOTAN_DLL operator<(const EAC_Time&, const EAC_Time&);
+
+bool BOTAN_DLL operator==(const ASN1_EAC_String&, const ASN1_EAC_String&);
+inline bool operator!=(const ASN1_EAC_String& lhs, const ASN1_EAC_String& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+}
+
+#endif
diff --git a/src/lib/cert/cvc/eac_obj.h b/src/lib/cert/cvc/eac_obj.h
new file mode 100644
index 000000000..42274446c
--- /dev/null
+++ b/src/lib/cert/cvc/eac_obj.h
@@ -0,0 +1,55 @@
+/*
+* EAC1_1 objects
+* (C) 2008 Falko Strenzke
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_EAC_OBJ_H__
+#define BOTAN_EAC_OBJ_H__
+
+#include <botan/signed_obj.h>
+#include <botan/ecdsa_sig.h>
+
+namespace Botan {
+
+/**
+* TR03110 v1.1 EAC CV Certificate
+*/
+template<typename Derived> // CRTP is used enable the call sequence:
+class EAC1_1_obj : public EAC_Signed_Object
+ {
+ public:
+ /**
+ * Return the signature as a concatenation of the encoded parts.
+ * @result the concatenated signature
+ */
+ std::vector<byte> get_concat_sig() const
+ { return m_sig.get_concatenation(); }
+
+ bool check_signature(class Public_Key& key) const
+ {
+ return EAC_Signed_Object::check_signature(key, m_sig.DER_encode());
+ }
+
+ protected:
+ ECDSA_Signature m_sig;
+
+ void init(DataSource& in)
+ {
+ try
+ {
+ Derived::decode_info(in, tbs_bits, m_sig);
+ }
+ catch(Decoding_Error)
+ {
+ throw Decoding_Error(PEM_label_pref + " decoding failed");
+ }
+ }
+
+ virtual ~EAC1_1_obj<Derived>(){}
+ };
+
+}
+
+#endif
diff --git a/src/lib/cert/cvc/ecdsa_sig.cpp b/src/lib/cert/cvc/ecdsa_sig.cpp
new file mode 100644
index 000000000..690244d50
--- /dev/null
+++ b/src/lib/cert/cvc/ecdsa_sig.cpp
@@ -0,0 +1,59 @@
+/*
+* ECDSA Signature
+* (C) 2007 Falko Strenzke, FlexSecure GmbH
+* (C) 2008-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/ecdsa_sig.h>
+
+namespace Botan {
+
+ECDSA_Signature::ECDSA_Signature(const std::vector<byte>& ber)
+ {
+ BER_Decoder(ber)
+ .start_cons(SEQUENCE)
+ .decode(m_r)
+ .decode(m_s)
+ .end_cons()
+ .verify_end();
+ }
+
+std::vector<byte> ECDSA_Signature::DER_encode() const
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(get_r())
+ .encode(get_s())
+ .end_cons()
+ .get_contents_unlocked();
+ }
+
+std::vector<byte> ECDSA_Signature::get_concatenation() const
+ {
+ // use the larger
+ const size_t enc_len = m_r > m_s ? m_r.bytes() : m_s.bytes();
+
+ const auto sv_r = BigInt::encode_1363(m_r, enc_len);
+ const auto sv_s = BigInt::encode_1363(m_s, enc_len);
+
+ secure_vector<byte> result(sv_r);
+ result += sv_s;
+ return unlock(result);
+ }
+
+ECDSA_Signature decode_concatenation(const std::vector<byte>& concat)
+ {
+ if(concat.size() % 2 != 0)
+ throw Invalid_Argument("Erroneous length of signature");
+
+ const size_t rs_len = concat.size() / 2;
+
+ BigInt r = BigInt::decode(&concat[0], rs_len);
+ BigInt s = BigInt::decode(&concat[rs_len], rs_len);
+
+ return ECDSA_Signature(r, s);
+ }
+
+}
diff --git a/src/lib/cert/cvc/ecdsa_sig.h b/src/lib/cert/cvc/ecdsa_sig.h
new file mode 100644
index 000000000..1c3b506cb
--- /dev/null
+++ b/src/lib/cert/cvc/ecdsa_sig.h
@@ -0,0 +1,61 @@
+/*
+* ECDSA Signature
+* (C) 2007 Falko Strenzke, FlexSecure GmbH
+* (C) 2008-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ECDSA_SIGNATURE_H__
+#define BOTAN_ECDSA_SIGNATURE_H__
+
+#include <botan/bigint.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+
+namespace Botan {
+
+/**
+* Class representing an ECDSA signature
+*/
+class BOTAN_DLL ECDSA_Signature
+ {
+ public:
+ friend class ECDSA_Signature_Decoder;
+
+ ECDSA_Signature() {}
+ ECDSA_Signature(const BigInt& r, const BigInt& s) :
+ m_r(r), m_s(s) {}
+
+ ECDSA_Signature(const std::vector<byte>& ber);
+
+ const BigInt& get_r() const { return m_r; }
+ const BigInt& get_s() const { return m_s; }
+
+ /**
+ * return the r||s
+ */
+ std::vector<byte> get_concatenation() const;
+
+ std::vector<byte> DER_encode() const;
+
+ bool operator==(const ECDSA_Signature& other) const
+ {
+ return (get_r() == other.get_r() && get_s() == other.get_s());
+ }
+
+ private:
+ BigInt m_r;
+ BigInt m_s;
+ };
+
+inline bool operator!=(const ECDSA_Signature& lhs, const ECDSA_Signature& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ECDSA_Signature decode_concatenation(const std::vector<byte>& concatenation);
+
+}
+
+#endif
diff --git a/src/lib/cert/cvc/info.txt b/src/lib/cert/cvc/info.txt
new file mode 100644
index 000000000..1d8e54dc4
--- /dev/null
+++ b/src/lib/cert/cvc/info.txt
@@ -0,0 +1,36 @@
+define CARD_VERIFIABLE_CERTIFICATES 20131128
+load_on request
+
+<header:public>
+cvc_ado.h
+cvc_cert.h
+cvc_gen_cert.h
+cvc_req.h
+cvc_self.h
+eac_asn_obj.h
+eac_obj.h
+ecdsa_sig.h
+signed_obj.h
+</header:public>
+
+<source>
+asn1_eac_str.cpp
+asn1_eac_tm.cpp
+ecdsa_sig.cpp
+cvc_ado.cpp
+cvc_cert.cpp
+cvc_req.cpp
+cvc_self.cpp
+signed_obj.cpp
+</source>
+
+<requires>
+asn1
+bigint
+ecdsa
+filters
+libstate
+oid_lookup
+pem
+pubkey
+</requires>
diff --git a/src/lib/cert/cvc/signed_obj.cpp b/src/lib/cert/cvc/signed_obj.cpp
new file mode 100644
index 000000000..20226fbe7
--- /dev/null
+++ b/src/lib/cert/cvc/signed_obj.cpp
@@ -0,0 +1,96 @@
+/*
+* EAC SIGNED Object
+* (C) 1999-2010 Jack Lloyd
+* 2007 FlexSecure GmbH
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/signed_obj.h>
+#include <botan/pubkey.h>
+#include <botan/oids.h>
+#include <memory>
+
+namespace Botan {
+
+/*
+* Return a BER encoded X.509 object
+*/
+std::vector<byte> EAC_Signed_Object::BER_encode() const
+ {
+ Pipe ber;
+ ber.start_msg();
+ encode(ber, RAW_BER);
+ ber.end_msg();
+ return unlock(ber.read_all());
+ }
+
+/*
+* Return a PEM encoded X.509 object
+*/
+std::string EAC_Signed_Object::PEM_encode() const
+ {
+ Pipe pem;
+ pem.start_msg();
+ encode(pem, PEM);
+ pem.end_msg();
+ return pem.read_all_as_string();
+ }
+
+/*
+* Return the algorithm used to sign this object
+*/
+AlgorithmIdentifier EAC_Signed_Object::signature_algorithm() const
+ {
+ return sig_algo;
+ }
+
+bool EAC_Signed_Object::check_signature(Public_Key& pub_key,
+ const std::vector<byte>& sig) const
+ {
+ try
+ {
+ std::vector<std::string> sig_info =
+ split_on(OIDS::lookup(sig_algo.oid), '/');
+
+ if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name())
+ {
+ return false;
+ }
+
+ std::string padding = sig_info[1];
+ Signature_Format format =
+ (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;
+
+ std::vector<byte> to_sign = tbs_data();
+
+ PK_Verifier verifier(pub_key, padding, format);
+ return verifier.verify_message(to_sign, sig);
+ }
+ catch(...)
+ {
+ return false;
+ }
+ }
+
+/*
+* Try to decode the actual information
+*/
+void EAC_Signed_Object::do_decode()
+ {
+ try {
+ force_decode();
+ }
+ catch(Decoding_Error& e)
+ {
+ const std::string what = e.what();
+ throw Decoding_Error(PEM_label_pref + " decoding failed (" + what + ")");
+ }
+ catch(Invalid_Argument& e)
+ {
+ const std::string what = e.what();
+ throw Decoding_Error(PEM_label_pref + " decoding failed (" + what + ")");
+ }
+ }
+
+}
diff --git a/src/lib/cert/cvc/signed_obj.h b/src/lib/cert/cvc/signed_obj.h
new file mode 100644
index 000000000..ce2bd4dd7
--- /dev/null
+++ b/src/lib/cert/cvc/signed_obj.h
@@ -0,0 +1,96 @@
+/*
+* EAC SIGNED Object
+* (C) 2007 FlexSecure GmbH
+* 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_EAC_SIGNED_OBJECT_H__
+#define BOTAN_EAC_SIGNED_OBJECT_H__
+
+#include <botan/asn1_obj.h>
+#include <botan/key_constraint.h>
+#include <botan/x509_key.h>
+#include <botan/pipe.h>
+#include <vector>
+
+namespace Botan {
+
+/**
+* This class represents abstract signed EAC object
+*/
+class BOTAN_DLL EAC_Signed_Object
+ {
+ public:
+ /**
+ * Get the TBS (to-be-signed) data in this object.
+ * @return DER encoded TBS data of this object
+ */
+ virtual std::vector<byte> tbs_data() const = 0;
+
+ /**
+ * Get the signature of this object as a concatenation, i.e. if the
+ * signature consists of multiple parts (like in the case of ECDSA)
+ * these will be concatenated.
+ * @return signature as a concatenation of its parts
+ */
+
+ /*
+ NOTE: this is here only because abstract signature objects have
+ not yet been introduced
+ */
+ virtual std::vector<byte> get_concat_sig() const = 0;
+
+ /**
+ * Get the signature algorithm identifier used to sign this object.
+ * @result the signature algorithm identifier
+ */
+ AlgorithmIdentifier signature_algorithm() const;
+
+ /**
+ * Check the signature of this object.
+ * @param key the public key associated with this signed object
+ * @param sig the signature we are checking
+ * @return true if the signature was created by the private key
+ * associated with this public key
+ */
+ bool check_signature(class Public_Key& key,
+ const std::vector<byte>& sig) const;
+
+ /**
+ * Write this object DER encoded into a specified pipe.
+ * @param pipe the pipe to write the encoded object to
+ * @param encoding the encoding type to use
+ */
+ virtual void encode(Pipe& pipe,
+ X509_Encoding encoding = PEM) const = 0;
+
+ /**
+ * BER encode this object.
+ * @return result containing the BER representation of this object.
+ */
+ std::vector<byte> BER_encode() const;
+
+ /**
+ * PEM encode this object.
+ * @return result containing the PEM representation of this object.
+ */
+ std::string PEM_encode() const;
+
+ virtual ~EAC_Signed_Object() {}
+ protected:
+ void do_decode();
+ EAC_Signed_Object() {}
+
+ AlgorithmIdentifier sig_algo;
+ std::vector<byte> tbs_bits;
+ std::string PEM_label_pref;
+ std::vector<std::string> PEM_labels_allowed;
+ private:
+ virtual void force_decode() = 0;
+ };
+
+}
+
+#endif