1extern crate alloc;
21use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, KeyInit};
22use alloc::vec::Vec;
23use hmac::{Hmac, Mac};
24use p256::elliptic_curve::sec1::ToEncodedPoint;
25use sha2::{Digest, Sha256, Sha384};
26
27pub const CT_CHANGE_CIPHER_SPEC: u8 = 20;
28pub const CT_ALERT: u8 = 21;
29pub const CT_HANDSHAKE: u8 = 22;
30pub const CT_APPLICATION_DATA: u8 = 23;
31
32pub const HS_CLIENT_HELLO: u8 = 1;
33pub const HS_SERVER_HELLO: u8 = 2;
34pub const HS_NEW_SESSION_TICKET: u8 = 4;
35pub const HS_CERTIFICATE: u8 = 11;
36pub const HS_SERVER_KEY_EXCHANGE: u8 = 12;
37pub const HS_CERTIFICATE_REQUEST: u8 = 13;
38pub const HS_SERVER_HELLO_DONE: u8 = 14;
39pub const HS_CLIENT_KEY_EXCHANGE: u8 = 16;
40pub const HS_FINISHED: u8 = 20;
41
42const MAX_FRAGMENT: usize = 16384;
44
45#[derive(Debug, Clone, Copy, PartialEq)]
47pub enum HashAlg {
48 Sha256,
49 Sha384,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq)]
54pub struct Suite {
55 pub id: u16,
56 pub key_len: usize,
57 pub hash: HashAlg,
58}
59
60pub const SUITES: [Suite; 4] = [
62 Suite { id: 0xC02B, key_len: 16, hash: HashAlg::Sha256 }, Suite { id: 0xC02F, key_len: 16, hash: HashAlg::Sha256 }, Suite { id: 0xC02C, key_len: 32, hash: HashAlg::Sha384 }, Suite { id: 0xC030, key_len: 32, hash: HashAlg::Sha384 }, ];
67
68pub fn suite_by_id(id: u16) -> Option<Suite> {
69 SUITES.iter().copied().find(|s| s.id == id)
70}
71
72#[derive(Debug, Clone, PartialEq)]
73pub enum Tls12Error {
74 Io,
76 Alert(u8, u8),
78 Protocol(&'static str),
80 Crypto,
82}
83
84impl core::fmt::Display for Tls12Error {
85 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
86 write!(f, "{:?}", self)
87 }
88}
89
90impl core::error::Error for Tls12Error {}
91
92impl embedded_io::Error for Tls12Error {
93 fn kind(&self) -> embedded_io::ErrorKind {
94 embedded_io::ErrorKind::Other
95 }
96}
97
98pub fn hash(alg: HashAlg, data: &[u8]) -> Vec<u8> {
99 match alg {
100 HashAlg::Sha256 => Sha256::digest(data).to_vec(),
101 HashAlg::Sha384 => Sha384::digest(data).to_vec(),
102 }
103}
104
105fn hmac(alg: HashAlg, key: &[u8], parts: &[&[u8]]) -> Vec<u8> {
106 match alg {
107 HashAlg::Sha256 => {
108 let Ok(mut m) = <Hmac<Sha256> as Mac>::new_from_slice(key) else { return Vec::new() };
109 for p in parts {
110 m.update(p);
111 }
112 m.finalize().into_bytes().to_vec()
113 }
114 HashAlg::Sha384 => {
115 let Ok(mut m) = <Hmac<Sha384> as Mac>::new_from_slice(key) else { return Vec::new() };
116 for p in parts {
117 m.update(p);
118 }
119 m.finalize().into_bytes().to_vec()
120 }
121 }
122}
123
124pub fn prf(alg: HashAlg, secret: &[u8], label: &[u8], seed: &[u8], out_len: usize) -> Vec<u8> {
126 let mut out = Vec::with_capacity(out_len);
127 let mut a = hmac(alg, secret, &[label, seed]);
129 while out.len() < out_len {
130 let block = hmac(alg, secret, &[&a, label, seed]);
131 if block.is_empty() {
132 break;
133 }
134 out.extend_from_slice(&block);
135 a = hmac(alg, secret, &[&a]);
136 }
137 out.truncate(out_len);
138 out
139}
140
141enum Aead {
143 A128(alloc::boxed::Box<Aes128Gcm>),
144 A256(alloc::boxed::Box<Aes256Gcm>),
145}
146
147pub struct RecordCipher {
149 aead: Aead,
150 salt: [u8; 4],
151 seq: u64,
152}
153
154impl RecordCipher {
155 pub fn new(key: &[u8], iv: &[u8]) -> Option<Self> {
156 let aead = match key.len() {
157 16 => Aead::A128(alloc::boxed::Box::new(Aes128Gcm::new_from_slice(key).ok()?)),
158 32 => Aead::A256(alloc::boxed::Box::new(Aes256Gcm::new_from_slice(key).ok()?)),
159 _ => return None,
160 };
161 let salt: [u8; 4] = iv.get(..4)?.try_into().ok()?;
162 Some(Self { aead, salt, seq: 0 })
163 }
164
165 fn aad(&self, ctype: u8, len: usize) -> [u8; 13] {
166 let mut a = [0u8; 13];
167 a[..8].copy_from_slice(&self.seq.to_be_bytes());
168 a[8] = ctype;
169 a[9] = 3;
170 a[10] = 3;
171 a[11..].copy_from_slice(&(len as u16).to_be_bytes());
172 a
173 }
174
175 pub fn seal(&mut self, ctype: u8, plain: &[u8]) -> Vec<u8> {
177 let explicit = self.seq.to_be_bytes();
178 let mut nonce = [0u8; 12];
179 nonce[..4].copy_from_slice(&self.salt);
180 nonce[4..].copy_from_slice(&explicit);
181 let aad = self.aad(ctype, plain.len());
182 let mut buf = plain.to_vec();
183 let tag = match &self.aead {
184 Aead::A128(c) => c.encrypt_in_place_detached((&nonce).into(), &aad, &mut buf).map(|t| t.to_vec()),
185 Aead::A256(c) => c.encrypt_in_place_detached((&nonce).into(), &aad, &mut buf).map(|t| t.to_vec()),
186 }
187 .unwrap_or_default();
188 self.seq = self.seq.wrapping_add(1);
189 let body_len = 8 + buf.len() + tag.len();
190 let mut rec = Vec::with_capacity(5 + body_len);
191 rec.extend_from_slice(&[ctype, 3, 3]);
192 rec.extend_from_slice(&(body_len as u16).to_be_bytes());
193 rec.extend_from_slice(&explicit);
194 rec.extend_from_slice(&buf);
195 rec.extend_from_slice(&tag);
196 rec
197 }
198
199 pub fn open(&mut self, ctype: u8, payload: &[u8]) -> Result<Vec<u8>, Tls12Error> {
201 if payload.len() < 8 + 16 {
202 return Err(Tls12Error::Crypto);
203 }
204 let mut nonce = [0u8; 12];
205 nonce[..4].copy_from_slice(&self.salt);
206 nonce[4..].copy_from_slice(&payload[..8]);
207 let ct_len = payload.len() - 8 - 16;
208 let aad = self.aad(ctype, ct_len);
209 let mut buf = payload[8..8 + ct_len].to_vec();
210 let tag = &payload[8 + ct_len..];
211 let ok = match &self.aead {
212 Aead::A128(c) => c.decrypt_in_place_detached((&nonce).into(), &aad, &mut buf, tag.into()),
213 Aead::A256(c) => c.decrypt_in_place_detached((&nonce).into(), &aad, &mut buf, tag.into()),
214 };
215 ok.map_err(|_| Tls12Error::Crypto)?;
216 self.seq = self.seq.wrapping_add(1);
217 Ok(buf)
218 }
219}
220
221pub fn handshake_msg(kind: u8, body: &[u8]) -> Vec<u8> {
223 let mut m = Vec::with_capacity(4 + body.len());
224 m.push(kind);
225 m.extend_from_slice(&(body.len() as u32).to_be_bytes()[1..]);
226 m.extend_from_slice(body);
227 m
228}
229
230fn push_ext(out: &mut Vec<u8>, kind: u16, data: &[u8]) {
231 out.extend_from_slice(&kind.to_be_bytes());
232 out.extend_from_slice(&(data.len() as u16).to_be_bytes());
233 out.extend_from_slice(data);
234}
235
236pub fn client_hello(host: &str, random: &[u8; 32]) -> Vec<u8> {
238 let mut b = Vec::new();
239 b.extend_from_slice(&[3, 3]);
240 b.extend_from_slice(random);
241 b.push(0); b.extend_from_slice(&((SUITES.len() * 2) as u16).to_be_bytes());
243 for s in SUITES {
244 b.extend_from_slice(&s.id.to_be_bytes());
245 }
246 b.extend_from_slice(&[1, 0]); let mut ext = Vec::new();
248 if !host.is_empty() && host.parse::<core::net::Ipv4Addr>().is_err() {
249 let name = host.as_bytes();
250 let mut sni = Vec::new();
251 sni.extend_from_slice(&((name.len() + 3) as u16).to_be_bytes());
252 sni.push(0);
253 sni.extend_from_slice(&(name.len() as u16).to_be_bytes());
254 sni.extend_from_slice(name);
255 push_ext(&mut ext, 0x0000, &sni);
256 }
257 push_ext(&mut ext, 0x000a, &[0, 2, 0, 23]); push_ext(&mut ext, 0x000b, &[1, 0]); let algs: [u16; 9] = [0x0403, 0x0804, 0x0805, 0x0806, 0x0401, 0x0501, 0x0601, 0x0503, 0x0201];
262 let mut sa = Vec::new();
263 sa.extend_from_slice(&((algs.len() * 2) as u16).to_be_bytes());
264 for a in algs {
265 sa.extend_from_slice(&a.to_be_bytes());
266 }
267 push_ext(&mut ext, 0x000d, &sa);
268 push_ext(&mut ext, 0xff01, &[0]); b.extend_from_slice(&(ext.len() as u16).to_be_bytes());
270 b.extend_from_slice(&ext);
271 handshake_msg(HS_CLIENT_HELLO, &b)
272}
273
274pub fn parse_server_hello(body: &[u8]) -> Result<([u8; 32], Suite), Tls12Error> {
276 let bad = Tls12Error::Protocol("ServerHello");
277 if body.get(..2) != Some(&[3, 3]) {
278 return Err(Tls12Error::Protocol("ServerHello: TLS 1.2 以外"));
279 }
280 let random: [u8; 32] = body.get(2..34).ok_or(bad.clone())?.try_into().map_err(|_| bad.clone())?;
281 let sid_len = *body.get(34).ok_or(bad.clone())? as usize;
282 let p = 35 + sid_len;
283 let id = u16::from_be_bytes([*body.get(p).ok_or(bad.clone())?, *body.get(p + 1).ok_or(bad.clone())?]);
284 let suite = suite_by_id(id).ok_or(Tls12Error::Protocol("ServerHello: 未対応のスイート"))?;
285 if body.get(p + 2) != Some(&0) {
286 return Err(Tls12Error::Protocol("ServerHello: 圧縮"));
287 }
288 Ok((random, suite))
289}
290
291pub fn parse_server_key_exchange(body: &[u8]) -> Result<Vec<u8>, Tls12Error> {
293 if body.first() != Some(&3) || body.get(1..3) != Some(&[0, 23]) {
294 return Err(Tls12Error::Protocol("ServerKeyExchange: secp256r1 以外"));
295 }
296 let n = *body.get(3).ok_or(Tls12Error::Protocol("ServerKeyExchange"))? as usize;
297 body.get(4..4 + n)
298 .map(|s| s.to_vec())
299 .ok_or(Tls12Error::Protocol("ServerKeyExchange"))
300}
301
302pub struct Keys {
304 pub master: Vec<u8>,
305 pub client_key: Vec<u8>,
306 pub server_key: Vec<u8>,
307 pub client_iv: Vec<u8>,
308 pub server_iv: Vec<u8>,
309}
310
311pub fn derive_keys(suite: Suite, premaster: &[u8], client_random: &[u8; 32], server_random: &[u8; 32]) -> Keys {
313 let mut seed = Vec::with_capacity(64);
314 seed.extend_from_slice(client_random);
315 seed.extend_from_slice(server_random);
316 let master = prf(suite.hash, premaster, b"master secret", &seed, 48);
317 let mut seed2 = Vec::with_capacity(64);
318 seed2.extend_from_slice(server_random);
319 seed2.extend_from_slice(client_random);
320 let k = suite.key_len;
321 let block = prf(suite.hash, &master, b"key expansion", &seed2, 2 * k + 8);
322 Keys {
323 client_key: block[..k].to_vec(),
324 server_key: block[k..2 * k].to_vec(),
325 client_iv: block[2 * k..2 * k + 4].to_vec(),
326 server_iv: block[2 * k + 4..2 * k + 8].to_vec(),
327 master,
328 }
329}
330
331pub fn verify_data(suite: Suite, master: &[u8], label: &[u8], transcript: &[u8]) -> Vec<u8> {
333 prf(suite.hash, master, label, &hash(suite.hash, transcript), 12)
334}
335
336pub struct Tls12<T> {
338 io: T,
339 rx: Vec<u8>,
340 read_cipher: Option<RecordCipher>,
341 write_cipher: Option<RecordCipher>,
342 hs_buf: Vec<u8>,
343 app: Vec<u8>,
344 app_pos: usize,
345 eof: bool,
346}
347
348impl<T: embedded_io::Read + embedded_io::Write> Tls12<T> {
349 pub fn connect(io: T, host: &str, rng: &mut impl rand_core::CryptoRngCore) -> Result<Self, Tls12Error> {
351 let mut c = Self {
352 io,
353 rx: Vec::new(),
354 read_cipher: None,
355 write_cipher: None,
356 hs_buf: Vec::new(),
357 app: Vec::new(),
358 app_pos: 0,
359 eof: false,
360 };
361 let mut client_random = [0u8; 32];
362 rng.fill_bytes(&mut client_random);
363 let mut transcript = Vec::new();
364
365 let ch = client_hello(host, &client_random);
366 transcript.extend_from_slice(&ch);
367 c.write_record(CT_HANDSHAKE, &ch)?;
368
369 let (kind, body) = c.next_handshake(&mut transcript)?;
370 if kind != HS_SERVER_HELLO {
371 return Err(Tls12Error::Protocol("ServerHello が来ない"));
372 }
373 let (server_random, suite) = parse_server_hello(&body)?;
374
375 let mut server_pub: Option<Vec<u8>> = None;
376 let mut cert_requested = false;
377 loop {
378 let (kind, body) = c.next_handshake(&mut transcript)?;
379 match kind {
380 HS_CERTIFICATE => {}
381 HS_SERVER_KEY_EXCHANGE => server_pub = Some(parse_server_key_exchange(&body)?),
382 HS_CERTIFICATE_REQUEST => cert_requested = true,
383 HS_SERVER_HELLO_DONE => break,
384 _ => {}
386 }
387 }
388 let server_pub = server_pub.ok_or(Tls12Error::Protocol("ServerKeyExchange が無い"))?;
389 let server_pk = p256::PublicKey::from_sec1_bytes(&server_pub).map_err(|_| Tls12Error::Crypto)?;
390 let secret = p256::ecdh::EphemeralSecret::random(rng);
391 let my_pub = secret.public_key().to_encoded_point(false);
392 let shared = secret.diffie_hellman(&server_pk);
393 let keys = derive_keys(suite, shared.raw_secret_bytes(), &client_random, &server_random);
394
395 let mut flight = Vec::new();
396 if cert_requested {
397 flight.extend_from_slice(&handshake_msg(HS_CERTIFICATE, &[0, 0, 0]));
399 }
400 let mut cke = Vec::with_capacity(66);
401 cke.push(my_pub.as_bytes().len() as u8);
402 cke.extend_from_slice(my_pub.as_bytes());
403 flight.extend_from_slice(&handshake_msg(HS_CLIENT_KEY_EXCHANGE, &cke));
404 transcript.extend_from_slice(&flight);
405 c.write_record(CT_HANDSHAKE, &flight)?;
406 c.write_record(CT_CHANGE_CIPHER_SPEC, &[1])?;
407 c.write_cipher = Some(RecordCipher::new(&keys.client_key, &keys.client_iv).ok_or(Tls12Error::Crypto)?);
408 let fin = handshake_msg(HS_FINISHED, &verify_data(suite, &keys.master, b"client finished", &transcript));
409 transcript.extend_from_slice(&fin);
410 c.write_record(CT_HANDSHAKE, &fin)?;
411
412 loop {
414 if c.hs_buf.is_empty() {
415 let (ctype, data) = c.read_record()?;
416 match ctype {
417 CT_CHANGE_CIPHER_SPEC => break,
418 CT_HANDSHAKE => c.hs_buf.extend_from_slice(&data),
419 _ => return Err(Tls12Error::Protocol("ChangeCipherSpec が来ない")),
420 }
421 } else {
422 let (kind, _) = c.next_handshake(&mut transcript)?;
423 if kind != HS_NEW_SESSION_TICKET {
424 return Err(Tls12Error::Protocol("想定外のハンドシェイク"));
425 }
426 }
427 }
428 c.read_cipher = Some(RecordCipher::new(&keys.server_key, &keys.server_iv).ok_or(Tls12Error::Crypto)?);
429 let expected = verify_data(suite, &keys.master, b"server finished", &transcript);
430 let (kind, body) = c.next_handshake(&mut transcript)?;
431 if kind != HS_FINISHED || body != expected {
432 return Err(Tls12Error::Crypto);
433 }
434 Ok(c)
435 }
436
437 fn write_record(&mut self, ctype: u8, data: &[u8]) -> Result<(), Tls12Error> {
439 for chunk in data.chunks(MAX_FRAGMENT) {
440 let rec = match self.write_cipher.as_mut() {
441 Some(w) => w.seal(ctype, chunk),
442 None => {
443 let mut r = Vec::with_capacity(5 + chunk.len());
444 r.extend_from_slice(&[ctype, 3, 3]);
445 r.extend_from_slice(&(chunk.len() as u16).to_be_bytes());
446 r.extend_from_slice(chunk);
447 r
448 }
449 };
450 self.io.write_all(&rec).map_err(|_| Tls12Error::Io)?;
451 }
452 self.io.flush().map_err(|_| Tls12Error::Io)
453 }
454
455 fn read_record(&mut self) -> Result<(u8, Vec<u8>), Tls12Error> {
457 loop {
458 if self.rx.len() >= 5 {
459 let len = u16::from_be_bytes([self.rx[3], self.rx[4]]) as usize;
460 if len > MAX_FRAGMENT + 2048 {
461 return Err(Tls12Error::Protocol("レコードが長すぎる"));
462 }
463 if self.rx.len() >= 5 + len {
464 let ctype = self.rx[0];
465 let payload: Vec<u8> = self.rx.drain(..5 + len).skip(5).collect();
466 let plain = match (ctype, self.read_cipher.as_mut()) {
467 (CT_CHANGE_CIPHER_SPEC, _) | (_, None) => payload,
468 (_, Some(r)) => r.open(ctype, &payload)?,
469 };
470 if ctype == CT_ALERT {
471 let level = plain.first().copied().unwrap_or(2);
472 let desc = plain.get(1).copied().unwrap_or(0);
473 return Err(Tls12Error::Alert(level, desc));
474 }
475 return Ok((ctype, plain));
476 }
477 }
478 let mut buf = [0u8; 2048];
479 match self.io.read(&mut buf) {
480 Ok(0) | Err(_) => return Err(Tls12Error::Io),
481 Ok(n) => self.rx.extend_from_slice(&buf[..n]),
482 }
483 }
484 }
485
486 fn next_handshake(&mut self, transcript: &mut Vec<u8>) -> Result<(u8, Vec<u8>), Tls12Error> {
488 loop {
489 if self.hs_buf.len() >= 4 {
490 let len = u32::from_be_bytes([0, self.hs_buf[1], self.hs_buf[2], self.hs_buf[3]]) as usize;
491 if self.hs_buf.len() >= 4 + len {
492 let msg: Vec<u8> = self.hs_buf.drain(..4 + len).collect();
493 transcript.extend_from_slice(&msg);
494 return Ok((msg[0], msg[4..].to_vec()));
495 }
496 }
497 let (ctype, data) = self.read_record()?;
498 if ctype != CT_HANDSHAKE {
499 return Err(Tls12Error::Protocol("ハンドシェイク中に別種のレコード"));
500 }
501 self.hs_buf.extend_from_slice(&data);
502 }
503 }
504
505 pub fn close(&mut self) {
507 let _ = self.write_record(CT_ALERT, &[1, 0]);
508 }
509}
510
511impl<T> embedded_io::ErrorType for Tls12<T> {
512 type Error = Tls12Error;
513}
514
515impl<T: embedded_io::Read + embedded_io::Write> embedded_io::Read for Tls12<T> {
516 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Tls12Error> {
517 while self.app_pos >= self.app.len() {
518 if self.eof {
519 return Ok(0);
520 }
521 match self.read_record() {
522 Ok((CT_APPLICATION_DATA, data)) => {
523 self.app = data;
524 self.app_pos = 0;
525 }
526 Ok(_) => {}
528 Err(Tls12Error::Alert(_, 0)) | Err(Tls12Error::Io) => self.eof = true,
530 Err(e) => return Err(e),
531 }
532 }
533 let n = buf.len().min(self.app.len() - self.app_pos);
534 buf[..n].copy_from_slice(&self.app[self.app_pos..self.app_pos + n]);
535 self.app_pos += n;
536 Ok(n)
537 }
538}
539
540impl<T: embedded_io::Read + embedded_io::Write> embedded_io::Write for Tls12<T> {
541 fn write(&mut self, buf: &[u8]) -> Result<usize, Tls12Error> {
542 self.write_record(CT_APPLICATION_DATA, buf)?;
543 Ok(buf.len())
544 }
545
546 fn flush(&mut self) -> Result<(), Tls12Error> {
547 self.io.flush().map_err(|_| Tls12Error::Io)
548 }
549}