/* * Decode BER encoded parameters */ void DL_Group::BER_decode(const std::vector<byte>& data, Format format) { BigInt new_p, new_q, new_g; BER_Decoder decoder(data); BER_Decoder ber = decoder.start_cons(SEQUENCE); if(format == ANSI_X9_57) { ber.decode(new_p) .decode(new_q) .decode(new_g) .verify_end(); } else if(format == ANSI_X9_42) { ber.decode(new_p) .decode(new_g) .decode(new_q) .discard_remaining(); } else if(format == PKCS_3) { ber.decode(new_p) .decode(new_g) .discard_remaining(); } else throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); initialize(new_p, new_q, new_g); }
/* * Decode a BER encoded DistinguishedName */ void X509_DN::decode_from(BER_Decoder& source) { MemoryVector<byte> bits; source.start_cons(SEQUENCE) .raw_bytes(bits) .end_cons(); BER_Decoder sequence(bits); while(sequence.more_items()) { BER_Decoder rdn = sequence.start_cons(SET); while(rdn.more_items()) { OID oid; ASN1_String str; rdn.start_cons(SEQUENCE) .decode(oid) .decode(str) .verify_end() .end_cons(); add_attribute(oid, str.value()); } } dn_bits = bits; }
Response::Response(const uint8_t response_bits[], size_t response_bits_len) : m_response_bits(response_bits, response_bits + response_bits_len) { m_dummy_response_status = Certificate_Status_Code::OCSP_RESPONSE_INVALID; BER_Decoder response_outer = BER_Decoder(m_response_bits).start_cons(SEQUENCE); size_t resp_status = 0; response_outer.decode(resp_status, ENUMERATED, UNIVERSAL); if(resp_status != 0) throw Exception("OCSP response status " + std::to_string(resp_status)); if(response_outer.more_items()) { BER_Decoder response_bytes = response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE); response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"), "Unknown response type in OCSP response"); BER_Decoder basicresponse = BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); basicresponse.start_cons(SEQUENCE) .raw_bytes(m_tbs_bits) .end_cons() .decode(m_sig_algo) .decode(m_signature, BIT_STRING); decode_optional_list(basicresponse, ASN1_Tag(0), m_certs); size_t responsedata_version = 0; Extensions extensions; BER_Decoder(m_tbs_bits) .decode_optional(responsedata_version, ASN1_Tag(0), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode_optional(m_signer_name, ASN1_Tag(1), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode_optional_string(m_key_hash, OCTET_STRING, 2, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode(m_produced_at) .decode_list(m_responses) .decode_optional(extensions, ASN1_Tag(1), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); } response_outer.end_cons(); }
/* * 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()); } }
/* * Decode a BER encoded AlgorithmIdentifier */ void AlgorithmIdentifier::decode_from(BER_Decoder& codec) { codec.start_cons(SEQUENCE) .decode(oid) .raw_bytes(parameters) .end_cons(); }
/* * 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"); } }
/* * Decompress a message */ void CMS_Decoder::decompress(BER_Decoder& decoder) { size_t version; AlgorithmIdentifier comp_algo; BER_Decoder comp_info = decoder.start_cons(SEQUENCE); comp_info.decode(version); if(version != 0) throw Decoding_Error("CMS: Unknown version for CompressedData"); comp_info.decode(comp_algo); read_econtent(comp_info); comp_info.end_cons(); Filter* decompressor = 0; info = comp_algo.oid.as_string(); #if defined(BOTAN_HAS_COMPRESSOR_ZLIB) if(comp_algo.oid == OIDS::lookup("Compression.Zlib")) { decompressor = new Zlib_Decompression; info = "Zlib"; } #endif if(!decompressor) status = FAILURE; Pipe pipe(decompressor); pipe.process_msg(data); data = pipe.read_all(); }
/* * Decode a BER encoded Attribute */ void Attribute::decode_from(BER_Decoder& codec) { codec.start_cons(SEQUENCE) .decode(oid) .start_cons(SET) .raw_bytes(parameters) .end_cons() .end_cons(); }
void X509_Time::decode_from(BER_Decoder& source) { BER_Object ber_time = source.get_next_object(); set_to(Charset::transcode(ASN1::to_string(ber_time), LATIN1_CHARSET, LOCAL_CHARSET), ber_time.type_tag); }
/* * Decode a BER encoded CRL_Entry */ void CRL_Entry::decode_from(BER_Decoder& source) { BigInt serial_number_bn; source.start_cons(SEQUENCE) .decode(serial_number_bn) .decode(time); if(source.more_items()) { Extensions extensions(throw_on_unknown_critical); source.decode(extensions); Data_Store info; extensions.contents_to(info, info); reason = CRL_Code(info.get1_u32bit("X509v3.CRLReasonCode")); } serial = BigInt::encode(serial_number_bn); }
/* * Read a BER encoded X.509 object */ void X509_Object::decode_from(BER_Decoder& from) { from.start_cons(SEQUENCE) .start_cons(SEQUENCE) .raw_bytes(m_tbs_bits) .end_cons() .decode(m_sig_algo) .decode(m_sig, BIT_STRING) .verify_end() .end_cons(); }
/* * Decode a BER encoded CRL_Entry */ void CRL_Entry::decode_from(BER_Decoder& source) { BigInt serial_number_bn; std::unique_ptr<CRL_Entry_Data> data(new CRL_Entry_Data); BER_Decoder entry = source.start_cons(SEQUENCE); entry.decode(serial_number_bn).decode(data->m_time); data->m_serial = BigInt::encode(serial_number_bn); if(entry.more_items()) { entry.decode(data->m_extensions); if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_ReasonCode>()) { data->m_reason = ext->get_reason(); } else { data->m_reason = UNSPECIFIED; } } entry.end_cons(); m_data.reset(data.release()); }
/* * Decode a BER encoded ASN1_String */ void ASN1_String::decode_from(BER_Decoder& source) { BER_Object obj = source.get_next_object(); Character_Set charset_is; if(obj.type_tag == BMP_STRING) charset_is = UCS2_CHARSET; else if(obj.type_tag == UTF8_STRING) charset_is = UTF8_CHARSET; else charset_is = LATIN1_CHARSET; *this = ASN1_String( Charset::transcode(ASN1::to_string(obj), charset_is, LOCAL_CHARSET), obj.type_tag); }
/* * 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::string message("decoding type mismatch for ASN1_EAC_String, tag is "); std::stringstream ss; std::string str_is; ss << std::hex << obj.type_tag; ss >> str_is; message.append(str_is); message.append(", while it should be "); std::stringstream ss2; std::string str_should; ss2 << std::hex << this->tag; ss2 >> str_should; message.append(str_should); throw Decoding_Error(message); }
/* * Decode a BER encoded KeyUsage */ void decode(BER_Decoder& source, Key_Constraints& key_usage) { BER_Object obj = source.get_next_object(); if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL) throw BER_Bad_Tag("Bad tag for usage constraint", obj.type_tag, obj.class_tag); if(obj.value.size() != 2 && obj.value.size() != 3) throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); if(obj.value[0] >= 8) throw BER_Decoding_Error("Invalid unused bits in usage constraint"); const byte mask = (0xFF << obj.value[0]); obj.value[obj.value.size()-1] &= mask; u16bit usage = 0; for(u32bit j = 1; j != obj.value.size(); ++j) usage = (obj.value[j] << 8) | usage; key_usage = Key_Constraints(usage); }
bool ne7ssh_keys::getDSAKeys (char* buffer, uint32 size) { // DataSource_Memory privKeyPEMSrc (privKeyPEMStr); const char* headerDSA = "-----BEGIN DSA PRIVATE KEY-----\n"; const char* footerDSA = "-----END DSA PRIVATE KEY-----\n"; SecureVector<Botan::byte> keyDataRaw; BigInt p, q, g, y, x; char *start; uint32 version; start = buffer + strlen(headerDSA); Pipe base64dec (new Base64_Decoder); base64dec.process_msg ((Botan::byte*)start, size - strlen(footerDSA) - strlen(headerDSA)); keyDataRaw = base64dec.read_all (PIPE_DEFAULT_MESSAGE); BER_Decoder decoder (keyDataRaw); #if BOTAN_PRE_15 BER_Decoder sequence = BER::get_subsequence(decoder); BER::decode (sequence, version); #else BER_Decoder sequence = decoder.start_cons (SEQUENCE); sequence.decode (version); #endif if (version) { ne7ssh::errors()->push (-1, "Encountered unknown DSA key version."); return false; } #if BOTAN_PRE_15 BER::decode (sequence, p); BER::decode (sequence, q); BER::decode (sequence, g); BER::decode (sequence, y); BER::decode (sequence, x); #else sequence.decode (p); sequence.decode (q); sequence.decode (g); sequence.decode (y); sequence.decode (x); #endif sequence.discard_remaining(); sequence.verify_end(); if (p.is_zero() || q.is_zero() || g.is_zero() || y.is_zero() || x.is_zero()) { ne7ssh::errors()->push (-1, "Could not decode the supplied DSA key."); return false; } DL_Group dsaGroup (p, q, g); #if BOTAN_PRE_18 || BOTAN_PRE_15 dsaPrivateKey = new DSA_PrivateKey (dsaGroup, x); #else dsaPrivateKey = new DSA_PrivateKey (*ne7ssh::rng, dsaGroup, x); #endif publicKeyBlob.clear(); publicKeyBlob.addString ("ssh-dss"); publicKeyBlob.addBigInt (p); publicKeyBlob.addBigInt (q); publicKeyBlob.addBigInt (g); publicKeyBlob.addBigInt (y); return true; }
Response::Response(const Certificate_Store& trusted_roots, const std::vector<byte>& response_bits) { BER_Decoder response_outer = BER_Decoder(response_bits).start_cons(SEQUENCE); size_t resp_status = 0; response_outer.decode(resp_status, ENUMERATED, UNIVERSAL); if(resp_status != 0) throw std::runtime_error("OCSP response status " + std::to_string(resp_status)); if(response_outer.more_items()) { BER_Decoder response_bytes = response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE); response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"), "Unknown response type in OCSP response"); BER_Decoder basicresponse = BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); std::vector<byte> tbs_bits; AlgorithmIdentifier sig_algo; std::vector<byte> signature; std::vector<X509_Certificate> certs; basicresponse.start_cons(SEQUENCE) .raw_bytes(tbs_bits) .end_cons() .decode(sig_algo) .decode(signature, BIT_STRING); decode_optional_list(basicresponse, ASN1_Tag(0), certs); size_t responsedata_version = 0; X509_DN name; std::vector<byte> key_hash; X509_Time produced_at; Extensions extensions; BER_Decoder(tbs_bits) .decode_optional(responsedata_version, ASN1_Tag(0), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode_optional(name, ASN1_Tag(1), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode_optional_string(key_hash, OCTET_STRING, 2, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) .decode(produced_at) .decode_list(m_responses) .decode_optional(extensions, ASN1_Tag(1), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); if(certs.empty()) { if(auto cert = trusted_roots.find_cert(name, std::vector<byte>())) certs.push_back(*cert); else throw std::runtime_error("Could not find certificate that signed OCSP response"); } check_signature(tbs_bits, sig_algo, signature, trusted_roots, certs); } response_outer.end_cons(); }
bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents, QList<BigInt> &pubKeyParams, QList<BigInt> &allKeyParams, QString &error) { try { bool syntaxOk = true; QList<QByteArray> lines = privKeyFileContents.split('\n'); while (lines.last().isEmpty()) lines.removeLast(); if (lines.count() < 3) { syntaxOk = false; } else if (lines.first() == PrivKeyFileStartLineRsa) { if (lines.last() != PrivKeyFileEndLineRsa) syntaxOk = false; else m_authKeyAlgoName = SshCapabilities::PubKeyRsa; } else if (lines.first() == PrivKeyFileStartLineDsa) { if (lines.last() != PrivKeyFileEndLineDsa) syntaxOk = false; else m_authKeyAlgoName = SshCapabilities::PubKeyDss; } else { syntaxOk = false; } if (!syntaxOk) { error = SSH_TR("Unexpected format."); return false; } QByteArray privateKeyBlob; for (int i = 1; i < lines.size() - 1; ++i) privateKeyBlob += lines.at(i); privateKeyBlob = QByteArray::fromBase64(privateKeyBlob); BER_Decoder decoder(convertByteArray(privateKeyBlob), privateKeyBlob.size()); BER_Decoder sequence = decoder.start_cons(SEQUENCE); size_t version; sequence.decode (version); if (version != 0) { error = SSH_TR("Key encoding has version %1, expected 0.").arg(version); return false; } if (m_authKeyAlgoName == SshCapabilities::PubKeyDss) { BigInt p, q, g, y, x; sequence.decode (p).decode (q).decode (g).decode (y).decode (x); DSA_PrivateKey * const dsaKey = new DSA_PrivateKey(m_rng, DL_Group(p, q, g), x); m_authKey.reset(dsaKey); pubKeyParams << p << q << g << y; allKeyParams << pubKeyParams << x; } else { BigInt p, q, e, d, n; sequence.decode(n).decode(e).decode(d).decode(p).decode(q); RSA_PrivateKey * const rsaKey = new RSA_PrivateKey(m_rng, p, q, e, d, n); m_authKey.reset(rsaKey); pubKeyParams << e << n; allKeyParams << pubKeyParams << p << q << d; } sequence.discard_remaining(); sequence.verify_end(); } catch (const Botan::Exception &ex) { error = QLatin1String(ex.what()); return false; } catch (const Botan::Decoding_Error &ex) { error = QLatin1String(ex.what()); return false; } return true; }
bool ne7ssh_keys::getRSAKeys (char* buffer, uint32 size) { const char* headerRSA = "-----BEGIN RSA PRIVATE KEY-----\n"; const char* footerRSA = "-----END RSA PRIVATE KEY-----\n"; SecureVector<Botan::byte> keyDataRaw; BigInt p, q, e, d, n; char *start; uint32 version; start = buffer + strlen(headerRSA); Pipe base64dec (new Base64_Decoder); base64dec.process_msg ((Botan::byte*)start, size - strlen(footerRSA) - strlen(headerRSA)); keyDataRaw = base64dec.read_all (PIPE_DEFAULT_MESSAGE); BER_Decoder decoder (keyDataRaw); #if BOTAN_PRE_15 BER_Decoder sequence = BER::get_subsequence(decoder); BER::decode (sequence, version); #else BER_Decoder sequence = decoder.start_cons(SEQUENCE); sequence.decode (version); #endif if (version) { ne7ssh::errors()->push (-1, "Encountered unknown RSA key version."); return false; } #if BOTAN_PRE_15 BER::decode (sequence, n); BER::decode (sequence, e); BER::decode (sequence, d); BER::decode (sequence, p); BER::decode (sequence, q); #else sequence.decode (n); sequence.decode (e); sequence.decode (d); sequence.decode (p); sequence.decode (q); #endif sequence.discard_remaining(); sequence.verify_end(); if (n.is_zero() || e.is_zero() || d.is_zero() || p.is_zero() || q.is_zero()) { ne7ssh::errors()->push (-1, "Could not decode the supplied RSA key."); return false; } #if BOTAN_PRE_18 || BOTAN_PRE_15 rsaPrivateKey = new RSA_PrivateKey (p, q, e, d, n); #else rsaPrivateKey = new RSA_PrivateKey (*ne7ssh::rng, p, q, e, d, n); #endif publicKeyBlob.clear(); publicKeyBlob.addString ("ssh-rsa"); publicKeyBlob.addBigInt (e); publicKeyBlob.addBigInt (n); return true; }
bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents, QList<BigInt> &pubKeyParams, QList<BigInt> &allKeyParams, QString &error) { try { bool syntaxOk = true; QList<QByteArray> lines = privKeyFileContents.split('\n'); while (lines.last().isEmpty()) lines.removeLast(); if (lines.count() < 3) { syntaxOk = false; } else if (lines.first() == PrivKeyFileStartLineRsa) { if (lines.last() != PrivKeyFileEndLineRsa) syntaxOk = false; else m_authKeyAlgoName = SshCapabilities::PubKeyRsa; } else if (lines.first() == PrivKeyFileStartLineDsa) { if (lines.last() != PrivKeyFileEndLineDsa) syntaxOk = false; else m_authKeyAlgoName = SshCapabilities::PubKeyDss; } else if (lines.first() == PrivKeyFileStartLineEcdsa) { if (lines.last() != PrivKeyFileEndLineEcdsa) syntaxOk = false; // m_authKeyAlgoName set below, as we don't know the size yet. } else { syntaxOk = false; } if (!syntaxOk) { error = SSH_TR("Unexpected format."); return false; } QByteArray privateKeyBlob; for (int i = 1; i < lines.size() - 1; ++i) privateKeyBlob += lines.at(i); privateKeyBlob = QByteArray::fromBase64(privateKeyBlob); BER_Decoder decoder(convertByteArray(privateKeyBlob), privateKeyBlob.size()); BER_Decoder sequence = decoder.start_cons(SEQUENCE); size_t version; sequence.decode (version); const size_t expectedVersion = m_authKeyAlgoName.isEmpty() ? 1 : 0; if (version != expectedVersion) { error = SSH_TR("Key encoding has version %1, expected %2.") .arg(version).arg(expectedVersion); return false; } if (m_authKeyAlgoName == SshCapabilities::PubKeyDss) { BigInt p, q, g, y, x; sequence.decode (p).decode (q).decode (g).decode (y).decode (x); DSA_PrivateKey * const dsaKey = new DSA_PrivateKey(m_rng, DL_Group(p, q, g), x); m_authKey.reset(dsaKey); pubKeyParams << p << q << g << y; allKeyParams << pubKeyParams << x; } else if (m_authKeyAlgoName == SshCapabilities::PubKeyRsa) { BigInt p, q, e, d, n; sequence.decode(n).decode(e).decode(d).decode(p).decode(q); RSA_PrivateKey * const rsaKey = new RSA_PrivateKey(m_rng, p, q, e, d, n); m_authKey.reset(rsaKey); pubKeyParams << e << n; allKeyParams << pubKeyParams << p << q << d; } else { BigInt privKey; sequence.decode_octet_string_bigint(privKey); m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth( static_cast<int>(privKey.bytes())); const EC_Group group(SshCapabilities::oid(m_authKeyAlgoName)); auto * const key = new ECDSA_PrivateKey(m_rng, group, privKey); m_authKey.reset(key); pubKeyParams << key->public_point().get_affine_x() << key->public_point().get_affine_y(); allKeyParams << pubKeyParams << privKey; } sequence.discard_remaining(); sequence.verify_end(); } catch (const Exception &ex) { error = QLatin1String(ex.what()); return false; } catch (const Decoding_Error &ex) { error = QLatin1String(ex.what()); return false; } return true; }
void X509_Time::decode_from(BER_Decoder& source) { BER_Object ber_time = source.get_next_object(); set_to(ASN1::to_string(ber_time), ber_time.type()); }