/* * PEM Encoding/Decoding * (C) 1999-2007 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #include #include namespace Botan { namespace PEM_Code { namespace { std::string linewrap(size_t width, const std::string& in) { std::string out; for(size_t i = 0; i != in.size(); ++i) { if(i > 0 && i % width == 0) { out.push_back('\n'); } out.push_back(in[i]); } if(out.size() > 0 && out[out.size()-1] != '\n') { out.push_back('\n'); } return out; } } /* * PEM encode BER/DER-encoded objects */ std::string encode(const byte der[], size_t length, const std::string& label, size_t width) { const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n"; const std::string PEM_TRAILER = "-----END " + label + "-----\n"; return (PEM_HEADER + linewrap(width, base64_encode(der, length)) + PEM_TRAILER); } /* * Decode PEM down to raw BER/DER */ secure_vector decode_check_label(DataSource& source, const std::string& label_want) { std::string label_got; secure_vector ber = decode(source, label_got); if(label_got != label_want) throw Decoding_Error("PEM: Label mismatch, wanted " + label_want + ", got " + label_got); return ber; } /* * Decode PEM down to raw BER/DER */ secure_vector decode(DataSource& source, std::string& label) { const size_t RANDOM_CHAR_LIMIT = 8; const std::string PEM_HEADER1 = "-----BEGIN "; const std::string PEM_HEADER2 = "-----"; size_t position = 0; while(position != PEM_HEADER1.length()) { byte b; if(!source.read_byte(b)) throw Decoding_Error("PEM: No PEM header found"); if(b == PEM_HEADER1[position]) ++position; else if(position >= RANDOM_CHAR_LIMIT) throw Decoding_Error("PEM: Malformed PEM header"); else position = 0; } position = 0; while(position != PEM_HEADER2.length()) { byte b; if(!source.read_byte(b)) throw Decoding_Error("PEM: No PEM header found"); if(b == PEM_HEADER2[position]) ++position; else if(position) throw Decoding_Error("PEM: Malformed PEM header"); if(position == 0) label += static_cast(b); } std::vector b64; const std::string PEM_TRAILER = "-----END " + label + "-----"; position = 0; while(position != PEM_TRAILER.length()) { byte b; if(!source.read_byte(b)) throw Decoding_Error("PEM: No PEM trailer found"); if(b == PEM_TRAILER[position]) ++position; else if(position) throw Decoding_Error("PEM: Malformed PEM trailer"); if(position == 0) b64.push_back(b); } return base64_decode(b64.data(), b64.size()); } secure_vector decode_check_label(const std::string& pem, const std::string& label_want) { DataSource_Memory src(pem); return decode_check_label(src, label_want); } secure_vector decode(const std::string& pem, std::string& label) { DataSource_Memory src(pem); return decode(src, label); } /* * Search for a PEM signature */ bool matches(DataSource& source, const std::string& extra, size_t search_range) { const std::string PEM_HEADER = "-----BEGIN " + extra; secure_vector search_buf(search_range); size_t got = source.peek(search_buf.data(), search_buf.size(), 0); if(got < PEM_HEADER.length()) return false; size_t index = 0; for(size_t j = 0; j != got; ++j) { if(search_buf[j] == PEM_HEADER[index]) ++index; else index = 0; if(index == PEM_HEADER.size()) return true; } return false; } } }