1 /*
2 * ngtcp2
3 *
4 * Copyright (c) 2020 ngtcp2 contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "util.h"
26
27 #include <cassert>
28 #include <iostream>
29 #include <fstream>
30 #include <array>
31
32 #include <ngtcp2/ngtcp2_crypto.h>
33
34 #include <gnutls/crypto.h>
35
36 #include "template.h"
37
38 // Based on https://github.com/ueno/ngtcp2-gnutls-examples
39
40 namespace ngtcp2 {
41
42 namespace util {
43
generate_secure_random(uint8_t * data,size_t datalen)44 int generate_secure_random(uint8_t *data, size_t datalen) {
45 if (gnutls_rnd(GNUTLS_RND_RANDOM, data, datalen) != 0) {
46 return -1;
47 }
48
49 return 0;
50 }
51
generate_secret(uint8_t * secret,size_t secretlen)52 int generate_secret(uint8_t *secret, size_t secretlen) {
53 std::array<uint8_t, 16> rand;
54 std::array<uint8_t, 32> md;
55
56 assert(md.size() == secretlen);
57
58 if (generate_secure_random(rand.data(), rand.size()) != 0) {
59 return -1;
60 }
61
62 if (gnutls_hash_fast(GNUTLS_DIG_SHA256, rand.data(), rand.size(),
63 md.data()) != 0) {
64 return -1;
65 }
66
67 std::copy_n(std::begin(md), secretlen, secret);
68 return 0;
69 }
70
read_token(const std::string_view & filename)71 std::optional<std::string> read_token(const std::string_view &filename) {
72 auto f = std::ifstream(filename.data());
73 if (!f) {
74 std::cerr << "Could not read token file " << filename << std::endl;
75 return {};
76 }
77
78 auto pos = f.tellg();
79 std::vector<char> content(pos);
80 f.seekg(0, std::ios::beg);
81 f.read(content.data(), pos);
82
83 gnutls_datum_t s;
84 s.data = reinterpret_cast<unsigned char *>(content.data());
85 s.size = content.size();
86
87 gnutls_datum_t d;
88 if (auto rv = gnutls_pem_base64_decode2("QUIC TOKEN", &s, &d); rv < 0) {
89 std::cerr << "Could not read token in " << filename << std::endl;
90 return {};
91 }
92
93 auto res = std::string{d.data, d.data + d.size};
94
95 gnutls_free(d.data);
96
97 return res;
98 }
99
write_token(const std::string_view & filename,const uint8_t * token,size_t tokenlen)100 int write_token(const std::string_view &filename, const uint8_t *token,
101 size_t tokenlen) {
102 auto f = std::ofstream(filename.data());
103 if (!f) {
104 std::cerr << "Could not write token in " << filename << std::endl;
105 return -1;
106 }
107
108 gnutls_datum_t s;
109 s.data = const_cast<uint8_t *>(token);
110 s.size = tokenlen;
111
112 gnutls_datum_t d;
113 if (auto rv = gnutls_pem_base64_encode2("QUIC TOKEN", &s, &d); rv < 0) {
114 std::cerr << "Could not encode token in " << filename << std::endl;
115 return -1;
116 }
117
118 f.write(reinterpret_cast<const char *>(d.data), d.size);
119 gnutls_free(d.data);
120
121 return 0;
122 }
123
crypto_aead_aes_128_gcm()124 ngtcp2_crypto_aead crypto_aead_aes_128_gcm() {
125 ngtcp2_crypto_aead aead;
126 ngtcp2_crypto_aead_init(&aead,
127 reinterpret_cast<void *>(GNUTLS_CIPHER_AES_128_GCM));
128 return aead;
129 }
130
crypto_md_sha256()131 ngtcp2_crypto_md crypto_md_sha256() {
132 ngtcp2_crypto_md md;
133 ngtcp2_crypto_md_init(&md, reinterpret_cast<void *>(GNUTLS_DIG_SHA256));
134 return md;
135 }
136
crypto_default_ciphers()137 const char *crypto_default_ciphers() {
138 return "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:"
139 "+CHACHA20-POLY1305:+AES-128-CCM";
140 }
141
crypto_default_groups()142 const char *crypto_default_groups() {
143 return "-GROUP-ALL:+GROUP-SECP256R1:+GROUP-X25519:+GROUP-SECP384R1:"
144 "+GROUP-SECP521R1";
145 }
146
147 } // namespace util
148
149 } // namespace ngtcp2
150