Line data Source code
1 : /*
2 : * Distributed under the OpenDDS License.
3 : * See: http://www.OpenDDS.org/license.html
4 : */
5 :
6 : #include "Utils.h"
7 :
8 : #include "Err.h"
9 :
10 : #include <dds/DCPS/Serializer.h>
11 : #include <dds/DCPS/GuidUtils.h>
12 :
13 : #include <dds/DdsDcpsCoreTypeSupportImpl.h>
14 :
15 : #include <openssl/evp.h>
16 : #include <openssl/rand.h>
17 : #include <openssl/err.h>
18 : #include "../OpenSSL_legacy.h" // Must come after all other OpenSSL includes
19 :
20 : #include <vector>
21 : #include <utility>
22 : #include <cstdio>
23 :
24 : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
25 :
26 : namespace OpenDDS {
27 : namespace Security {
28 : namespace SSL {
29 :
30 : using DCPS::Serializer;
31 : using DCPS::Encoding;
32 : using DCPS::serialized_size;
33 :
34 : namespace {
35 48 : Encoding get_common_encoding() {
36 48 : Encoding encoding(Encoding::KIND_XCDR1, DCPS::ENDIAN_BIG);
37 48 : return encoding;
38 : }
39 : }
40 :
41 46 : int make_adjusted_guid(const OpenDDS::DCPS::GUID_t& src,
42 : OpenDDS::DCPS::GUID_t& dst,
43 : const Certificate& target)
44 : {
45 46 : dst = OpenDDS::DCPS::GUID_UNKNOWN;
46 46 : dst.entityId = src.entityId;
47 :
48 46 : std::vector<unsigned char> hash;
49 46 : int result = target.subject_name_digest(hash);
50 :
51 46 : if (result == 0 && hash.size() >= 6) {
52 46 : unsigned char* bytes = reinterpret_cast<unsigned char*>(&dst);
53 :
54 322 : for (size_t i = 0; i < 6; ++i) { // First 6 bytes of guid prefix
55 276 : bytes[i] = offset_1bit(&hash[0], i);
56 : }
57 :
58 46 : bytes[0] |= 0x80;
59 :
60 : // Last 6 bytes of guid prefix = hash of src guid (candidate guid)
61 :
62 46 : unsigned char hash2[EVP_MAX_MD_SIZE] = {0};
63 46 : unsigned int len = 0u;
64 :
65 46 : EVP_MD_CTX* hash_ctx = EVP_MD_CTX_new();
66 46 : if (hash_ctx) {
67 46 : EVP_DigestInit_ex(hash_ctx, EVP_sha256(), 0);
68 46 : EVP_DigestUpdate(hash_ctx, &src, sizeof(OpenDDS::DCPS::GUID_t));
69 46 : EVP_DigestFinal_ex(hash_ctx, hash2, &len);
70 46 : if (len > 5) {
71 46 : std::memcpy(bytes + 6, hash2, 6);
72 : } else {
73 0 : result = 1;
74 : }
75 :
76 46 : EVP_MD_CTX_free(hash_ctx);
77 : }
78 : }
79 :
80 46 : return result;
81 46 : }
82 :
83 : template <size_t Bits>
84 17 : int make_nonce(std::vector<unsigned char>& nonce)
85 : {
86 17 : nonce.clear();
87 :
88 17 : unsigned char tmp[Bits / 8] = { 0 };
89 :
90 17 : if (RAND_bytes(tmp, sizeof tmp) == 1) {
91 17 : nonce.insert(nonce.begin(), tmp, tmp + sizeof tmp);
92 :
93 17 : return 0;
94 :
95 : } else {
96 0 : unsigned long err = ERR_get_error();
97 0 : char msg[256] = { 0 };
98 0 : ERR_error_string_n(err, msg, sizeof(msg));
99 :
100 0 : ACE_ERROR((LM_ERROR,
101 : ACE_TEXT("(%P|%t) SSL::make_nonce: ERROR '%C' returned by RAND_bytes(...)\n"),
102 : msg));
103 : }
104 :
105 0 : return 1;
106 : }
107 :
108 1 : int make_nonce_256(std::vector<unsigned char>& nonce)
109 : {
110 1 : return make_nonce<256>(nonce);
111 : }
112 :
113 16 : int make_nonce_256(DDS::OctetSeq& nonce)
114 : {
115 : /* A bit slower but the impl. for vectors is already complete */
116 16 : std::vector<unsigned char> tmp;
117 16 : int err = make_nonce<256>(tmp);
118 16 : if (!err) {
119 16 : nonce.length(static_cast<unsigned int>(tmp.size()));
120 528 : for (size_t i = 0; i < tmp.size(); ++i) {
121 512 : nonce[static_cast<unsigned int>(i)] = tmp[i];
122 : }
123 : }
124 16 : return err;
125 16 : }
126 :
127 348 : unsigned char offset_1bit(const unsigned char array[], size_t i)
128 : {
129 348 : return (array[i] >> 1) | (i == 0 ? 0 : ((array[i - 1] & 1) ? 0x80 : 0));
130 : }
131 :
132 14 : int hash(const std::vector<const DDS::OctetSeq*>& src, DDS::OctetSeq& dst)
133 : {
134 14 : EVP_MD_CTX* hash_ctx = EVP_MD_CTX_new();
135 14 : if (!hash_ctx) {
136 0 : OPENDDS_SSL_LOG_ERR("EVP_MD_CTX_new failed");
137 0 : return 1;
138 : }
139 :
140 14 : EVP_DigestInit_ex(hash_ctx, EVP_sha256(), 0);
141 :
142 14 : unsigned char hash[EVP_MAX_MD_SIZE] = { 0 };
143 14 : unsigned int len = 0u;
144 :
145 14 : std::vector<const DDS::OctetSeq*>::const_iterator i, n = src.end();
146 28 : for (i = src.begin(); i != n; ++i) {
147 14 : EVP_DigestUpdate(hash_ctx, (*i)->get_buffer(), (*i)->length());
148 : }
149 :
150 14 : EVP_DigestFinal_ex(hash_ctx, hash, &len);
151 :
152 14 : dst.length(len);
153 14 : std::memcpy(dst.get_buffer(), hash, len);
154 :
155 14 : EVP_MD_CTX_free(hash_ctx);
156 :
157 14 : return 0;
158 : }
159 :
160 : class hash_serialized_impl
161 : {
162 : public:
163 26 : hash_serialized_impl()
164 26 : : hash_ctx(EVP_MD_CTX_new())
165 : {
166 26 : if (!hash_ctx) {
167 0 : OPENDDS_SSL_LOG_ERR("EVP_MD_CTX_new failed");
168 : }
169 26 : }
170 :
171 26 : ~hash_serialized_impl()
172 : {
173 26 : if (hash_ctx) {
174 26 : EVP_MD_CTX_free(hash_ctx);
175 : }
176 26 : }
177 :
178 26 : int operator()(const DDS::BinaryPropertySeq& src, DDS::OctetSeq& dst)
179 : {
180 26 : if (!hash_ctx) return 1;
181 :
182 26 : EVP_DigestInit_ex(hash_ctx, EVP_sha256(), 0);
183 :
184 26 : const Encoding encoding = get_common_encoding();
185 26 : size_t size = 0;
186 26 : serialized_size(encoding, size, src);
187 26 : ACE_Message_Block buffer(size);
188 26 : Serializer serializer(&buffer, encoding);
189 26 : if (serializer << src) {
190 26 : EVP_DigestUpdate(hash_ctx, buffer.rd_ptr(), buffer.length());
191 :
192 26 : dst.length(EVP_MAX_MD_SIZE);
193 :
194 26 : unsigned int newlen = 0u;
195 26 : EVP_DigestFinal_ex(hash_ctx, dst.get_buffer(), &newlen);
196 :
197 26 : dst.length(newlen);
198 :
199 : } else {
200 0 : ACE_ERROR((LM_ERROR,
201 : ACE_TEXT("(%P|%t) SSL::hash_serialized_impl::operator(): ERROR, failed to "
202 : "serialize binary-property-sequence\n")));
203 :
204 0 : return 1;
205 : }
206 :
207 26 : return 0;
208 26 : }
209 :
210 : private:
211 : EVP_MD_CTX* hash_ctx;
212 : };
213 :
214 26 : int hash_serialized(const DDS::BinaryPropertySeq& src, DDS::OctetSeq& dst)
215 : {
216 26 : hash_serialized_impl hash;
217 52 : return hash(src, dst);
218 26 : }
219 :
220 12 : int sign_serialized(const DDS::BinaryPropertySeq& src,
221 : const PrivateKey& key, DDS::OctetSeq& dst)
222 : {
223 12 : const Encoding encoding = get_common_encoding();
224 12 : size_t size = 0;
225 12 : serialized_size(encoding, size, src);
226 :
227 12 : DDS::OctetSeq tmp;
228 12 : tmp.length(static_cast<unsigned int>(size));
229 24 : ACE_Message_Block buffer(reinterpret_cast<const char*>(tmp.get_buffer()),
230 12 : tmp.length());
231 12 : Serializer serializer(&buffer, encoding);
232 12 : if (!(serializer << src)) {
233 0 : ACE_ERROR((LM_ERROR,
234 : ACE_TEXT("(%P|%t) SSL::sign_serialized: ERROR, failed to serialize "
235 : "binary-property-sequence\n")));
236 :
237 0 : return 1;
238 : }
239 :
240 12 : std::vector<const DDS::OctetSeq*> sign_these;
241 12 : sign_these.push_back(&tmp);
242 :
243 12 : return key.sign(sign_these, dst);
244 12 : }
245 :
246 10 : int verify_serialized(const DDS::BinaryPropertySeq& src,
247 : const Certificate& key,
248 : const DDS::OctetSeq& signed_data)
249 : {
250 10 : const Encoding encoding = get_common_encoding();
251 10 : size_t size = 0;
252 10 : serialized_size(encoding, size, src);
253 :
254 10 : DDS::OctetSeq tmp;
255 10 : tmp.length(static_cast<unsigned int>(size));
256 20 : ACE_Message_Block buffer(reinterpret_cast<const char*>(tmp.get_buffer()),
257 10 : tmp.length());
258 10 : Serializer serializer(&buffer, encoding);
259 10 : if (!(serializer << src)) {
260 0 : ACE_ERROR((LM_ERROR,
261 : ACE_TEXT("(%P|%t) SSL::verify_serialized: ERROR, failed to serialize binary-property-sequence\n")));
262 :
263 0 : return 1;
264 : }
265 :
266 10 : std::vector<const DDS::OctetSeq*> verify_these;
267 10 : verify_these.push_back(&tmp);
268 :
269 10 : return key.verify_signature(signed_data, verify_these);
270 10 : }
271 :
272 : } // namespace SSL
273 : } // namespace Security
274 : } // namespace OpenDDS
275 :
276 : OPENDDS_END_VERSIONED_NAMESPACE_DECL
|