Botan 3.0.0
Crypto and TLS for C&
pem.cpp
Go to the documentation of this file.
1/*
2* PEM Encoding/Decoding
3* (C) 1999-2007 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/pem.h>
9#include <botan/data_src.h>
10#include <botan/base64.h>
11#include <botan/exceptn.h>
12#include <botan/internal/fmt.h>
13
14namespace Botan::PEM_Code {
15
16namespace {
17
18std::string linewrap(size_t width, std::string_view in)
19 {
20 std::string out;
21 for(size_t i = 0; i != in.size(); ++i)
22 {
23 if(i > 0 && i % width == 0)
24 {
25 out.push_back('\n');
26 }
27 out.push_back(in[i]);
28 }
29 if(!out.empty() && out[out.size()-1] != '\n')
30 {
31 out.push_back('\n');
32 }
33
34 return out;
35 }
36
37}
38
39/*
40* PEM encode BER/DER-encoded objects
41*/
42std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
43 {
44 const std::string PEM_HEADER = fmt("-----BEGIN {}-----\n", label);
45 const std::string PEM_TRAILER = fmt("-----END {}-----\n", label);
46
47 return (PEM_HEADER + linewrap(width, base64_encode(der, length)) + PEM_TRAILER);
48 }
49
50/*
51* Decode PEM down to raw BER/DER
52*/
54 std::string_view label_want)
55 {
56 std::string label_got;
57 secure_vector<uint8_t> ber = decode(source, label_got);
58 if(label_got != label_want)
59 {
60 throw Decoding_Error(fmt("PEM: Label mismatch, wanted '{}' got '{}'",
61 label_want, label_got));
62 }
63
64 return ber;
65 }
66
67/*
68* Decode PEM down to raw BER/DER
69*/
70secure_vector<uint8_t> decode(DataSource& source, std::string& label)
71 {
72 const size_t RANDOM_CHAR_LIMIT = 8;
73
74 label.clear();
75
76 const std::string PEM_HEADER1 = "-----BEGIN ";
77 const std::string PEM_HEADER2 = "-----";
78 size_t position = 0;
79
80 while(position != PEM_HEADER1.length())
81 {
82 uint8_t b;
83 if(!source.read_byte(b))
84 throw Decoding_Error("PEM: No PEM header found");
85 if(static_cast<char>(b) == PEM_HEADER1[position])
86 ++position;
87 else if(position >= RANDOM_CHAR_LIMIT)
88 throw Decoding_Error("PEM: Malformed PEM header");
89 else
90 position = 0;
91 }
92 position = 0;
93 while(position != PEM_HEADER2.length())
94 {
95 uint8_t b;
96 if(!source.read_byte(b))
97 throw Decoding_Error("PEM: No PEM header found");
98 if(static_cast<char>(b) == PEM_HEADER2[position])
99 ++position;
100 else if(position)
101 throw Decoding_Error("PEM: Malformed PEM header");
102
103 if(position == 0)
104 label += static_cast<char>(b);
105 }
106
107 std::vector<char> b64;
108
109 const std::string PEM_TRAILER = fmt("-----END {}-----", label);
110 position = 0;
111 while(position != PEM_TRAILER.length())
112 {
113 uint8_t b;
114 if(!source.read_byte(b))
115 throw Decoding_Error("PEM: No PEM trailer found");
116 if(static_cast<char>(b) == PEM_TRAILER[position])
117 ++position;
118 else if(position)
119 throw Decoding_Error("PEM: Malformed PEM trailer");
120
121 if(position == 0)
122 b64.push_back(b);
123 }
124
125 return base64_decode(b64.data(), b64.size());
126 }
127
129 std::string_view label_want)
130 {
131 DataSource_Memory src(pem);
132 return decode_check_label(src, label_want);
133 }
134
135secure_vector<uint8_t> decode(std::string_view pem, std::string& label)
136 {
137 DataSource_Memory src(pem);
138 return decode(src, label);
139 }
140
141/*
142* Search for a PEM signature
143*/
144bool matches(DataSource& source, std::string_view extra,
145 size_t search_range)
146 {
147 const std::string PEM_HEADER = fmt("-----BEGIN {}", extra);
148
149 secure_vector<uint8_t> search_buf(search_range);
150 const size_t got = source.peek(search_buf.data(), search_buf.size(), 0);
151
152 if(got < PEM_HEADER.length())
153 return false;
154
155 size_t index = 0;
156
157 for(size_t j = 0; j != got; ++j)
158 {
159 if(static_cast<char>(search_buf[j]) == PEM_HEADER[index])
160 {
161 ++index;
162 }
163 else
164 {
165 index = 0;
166 }
167
168 if(index == PEM_HEADER.size())
169 {
170 return true;
171 }
172 }
173
174 return false;
175 }
176
177}
size_t read_byte(uint8_t &out)
Definition: data_src.cpp:24
virtual size_t peek(uint8_t out[], size_t length, size_t peek_offset) const =0
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
Definition: pem.cpp:42
secure_vector< uint8_t > decode_check_label(DataSource &source, std::string_view label_want)
Definition: pem.cpp:53
bool matches(DataSource &source, std::string_view extra, size_t search_range)
Definition: pem.cpp:144
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:70
std::string fmt(std::string_view format, const T &... args)
Definition: fmt.h:60
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition: base64.cpp:178
size_t base64_decode(uint8_t out[], const char in[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws)
Definition: base64.cpp:193
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:64