1 /* Copyright (c) 2018, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include "settings_writer.h"
16 
17 #include <stdio.h>
18 
19 #include <openssl/ssl.h>
20 
21 #include "fuzzer_tags.h"
22 #include "test_config.h"
23 
24 
SettingsWriter()25 SettingsWriter::SettingsWriter() {}
26 
Init(int i,const TestConfig * config,SSL_SESSION * session)27 bool SettingsWriter::Init(int i, const TestConfig *config,
28                           SSL_SESSION *session) {
29   if (config->write_settings.empty()) {
30     return true;
31   }
32   // Treat write_settings as a path prefix for each connection in the run.
33   char buf[DECIMAL_SIZE(int)];
34   snprintf(buf, sizeof(buf), "%d", i);
35   path_ = config->write_settings + buf;
36 
37   if (!CBB_init(cbb_.get(), 64)) {
38     return false;
39   }
40 
41   if (session != nullptr) {
42     uint8_t *data;
43     size_t len;
44     if (!SSL_SESSION_to_bytes(session, &data, &len)) {
45       return false;
46     }
47     bssl::UniquePtr<uint8_t> free_data(data);
48     CBB child;
49     if (!CBB_add_u16(cbb_.get(), kSessionTag) ||
50         !CBB_add_u24_length_prefixed(cbb_.get(), &child) ||
51         !CBB_add_bytes(&child, data, len) || !CBB_flush(cbb_.get())) {
52       return false;
53     }
54   }
55 
56   if (config->is_server &&
57       (config->require_any_client_certificate || config->verify_peer) &&
58       !CBB_add_u16(cbb_.get(), kRequestClientCert)) {
59     return false;
60   }
61 
62   return true;
63 }
64 
Commit()65 bool SettingsWriter::Commit() {
66   if (path_.empty()) {
67     return true;
68   }
69 
70   uint8_t *settings;
71   size_t settings_len;
72   if (!CBB_add_u16(cbb_.get(), kDataTag) ||
73       !CBB_finish(cbb_.get(), &settings, &settings_len)) {
74     return false;
75   }
76   bssl::UniquePtr<uint8_t> free_settings(settings);
77 
78   using ScopedFILE = std::unique_ptr<FILE, decltype(&fclose)>;
79   ScopedFILE file(fopen(path_.c_str(), "w"), fclose);
80   if (!file) {
81     return false;
82   }
83 
84   return fwrite(settings, settings_len, 1, file.get()) == 1;
85 }
86 
WriteHandoff(bssl::Span<const uint8_t> handoff)87 bool SettingsWriter::WriteHandoff(bssl::Span<const uint8_t> handoff) {
88   if (path_.empty()) {
89     return true;
90   }
91 
92   CBB child;
93   if (!CBB_add_u16(cbb_.get(), kHandoffTag) ||
94       !CBB_add_u24_length_prefixed(cbb_.get(), &child) ||
95       !CBB_add_bytes(&child, handoff.data(), handoff.size()) ||
96       !CBB_flush(cbb_.get())) {
97     return false;
98   }
99   return true;
100 }
101 
WriteHandback(bssl::Span<const uint8_t> handback)102 bool SettingsWriter::WriteHandback(bssl::Span<const uint8_t> handback) {
103   if (path_.empty()) {
104     return true;
105   }
106 
107   CBB child;
108   if (!CBB_add_u16(cbb_.get(), kHandbackTag) ||
109       !CBB_add_u24_length_prefixed(cbb_.get(), &child) ||
110       !CBB_add_bytes(&child, handback.data(), handback.size()) ||
111       !CBB_flush(cbb_.get())) {
112     return false;
113   }
114   return true;
115 }
116