/************************************************* * X.509 SIGNED Object Source File * * (C) 1999-2006 The Botan Project * *************************************************/ #include #include #include #include #include #include #include #include #include #include namespace Botan { /************************************************* * Create a generic X.509 object * *************************************************/ X509_Object::X509_Object(DataSource& stream, const std::string& labels) { init(stream, labels); } /************************************************* * Createa a generic X.509 object * *************************************************/ X509_Object::X509_Object(const std::string& file, const std::string& labels) { DataSource_Stream stream(file, true); init(stream, labels); } /************************************************* * Read a PEM or BER X.509 object * *************************************************/ void X509_Object::init(DataSource& in, const std::string& labels) { PEM_labels_allowed = split_on(labels, '/'); if(PEM_labels_allowed.size() < 1) throw Invalid_Argument("Bad labels argument to X509_Object"); PEM_label_pref = PEM_labels_allowed[0]; std::sort(PEM_labels_allowed.begin(), PEM_labels_allowed.end()); try { if(ASN1::maybe_BER(in) && !PEM_Code::matches(in)) decode_info(in); else { std::string got_label; DataSource_Memory ber(PEM_Code::decode(in, got_label)); if(!std::binary_search(PEM_labels_allowed.begin(), PEM_labels_allowed.end(), got_label)) throw Decoding_Error("Invalid PEM label: " + got_label); decode_info(ber); } } catch(Decoding_Error) { throw Decoding_Error(PEM_label_pref + " decoding failed"); } } /************************************************* * Read a BER encoded X.509 object * *************************************************/ void X509_Object::decode_info(DataSource& source) { BER_Decoder(source) .start_cons(SEQUENCE) .start_cons(SEQUENCE) .raw_bytes(tbs_bits) .end_cons() .decode(sig_algo) .decode(sig, BIT_STRING) .verify_end() .end_cons(); } /************************************************* * Return a BER or PEM encoded X.509 object * *************************************************/ void X509_Object::encode(Pipe& out, X509_Encoding encoding) const { SecureVector der = DER_Encoder() .start_cons(SEQUENCE) .start_cons(SEQUENCE) .raw_bytes(tbs_bits) .end_cons() .encode(sig_algo) .encode(sig, BIT_STRING) .end_cons() .get_contents(); if(encoding == PEM) out.write(PEM_Code::encode(der, PEM_label_pref)); else out.write(der); } /************************************************* * Return a BER encoded X.509 object * *************************************************/ SecureVector X509_Object::BER_encode() const { Pipe ber; ber.start_msg(); encode(ber, RAW_BER); ber.end_msg(); return ber.read_all(); } /************************************************* * Return a PEM encoded X.509 object * *************************************************/ std::string X509_Object::PEM_encode() const { Pipe pem; pem.start_msg(); encode(pem, PEM); pem.end_msg(); return pem.read_all_as_string(); } /************************************************* * Return the TBS data * *************************************************/ SecureVector X509_Object::tbs_data() const { return ASN1::put_in_sequence(tbs_bits); } /************************************************* * Return the signature of this object * *************************************************/ SecureVector X509_Object::signature() const { return sig; } /************************************************* * Return the algorithm used to sign this object * *************************************************/ AlgorithmIdentifier X509_Object::signature_algorithm() const { return sig_algo; } /************************************************* * Check the signature on an object * *************************************************/ bool X509_Object::check_signature(Public_Key& pub_key) const { try { std::vector 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::auto_ptr verifier; if(dynamic_cast(&pub_key)) { PK_Verifying_with_MR_Key& sig_key = dynamic_cast(pub_key); verifier.reset(get_pk_verifier(sig_key, padding, format)); } else if(dynamic_cast(&pub_key)) { PK_Verifying_wo_MR_Key& sig_key = dynamic_cast(pub_key); verifier.reset(get_pk_verifier(sig_key, padding, format)); } else return false; return verifier->verify_message(tbs_data(), signature()); } catch(...) { return false; } } /************************************************* * Apply the X.509 SIGNED macro * *************************************************/ MemoryVector X509_Object::make_signed(PK_Signer* signer, const AlgorithmIdentifier& algo, const MemoryRegion& tbs_bits) { return DER_Encoder() .start_cons(SEQUENCE) .raw_bytes(tbs_bits) .encode(algo) .encode(signer->sign_message(tbs_bits), BIT_STRING) .end_cons() .get_contents(); } /************************************************* * Try to decode the actual information * *************************************************/ void X509_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.substr(23, std::string::npos) + ")"); } catch(Invalid_Argument& e) { const std::string what = e.what(); throw Decoding_Error(PEM_label_pref + " decoding failed (" + what.substr(7, std::string::npos) + ")"); } } }