Skip to main content

atmos/kernel/
tls12.rs

1//! TLS 1.2 クライアント(ECDHE + AES-GCM のみ)。
2//!
3//! 【2026-10-03】HTTPS は `embedded-tls`(**TLS 1.3 専用**)で行っているため、TLS 1.2 しか
4//! 話さないサーバーには接続できなかった。sugi-lab.net/smarthome.htm の Microsoft Sway 埋め込み
5//! (`sway.com`。`openssl s_client -tls1_3` で応答なし、TLS 1.2 では ECDHE-RSA-AES256-GCM-SHA384)
6//! がこれに当たり、iframe の中身を取得できなかった。TLS 1.2 のみのサーバーは今も多いので、
7//! TLS 1.3 のハンドシェイクが失敗したときの代替として最小限の TLS 1.2 を持つ。
8//!
9//! 対応範囲(RFC 5246 / 5289 / 8422):
10//! - 暗号スイート: ECDHE_{ECDSA,RSA}_WITH_AES_{128_GCM_SHA256,256_GCM_SHA384}
11//! - 鍵交換の曲線: secp256r1 のみ、点は非圧縮のみ
12//! - 証明書・ServerKeyExchange の署名は**検証しない**(TLS 1.3 側も `UnsecureProvider` で
13//!   検証していないのと同じ水準。証明書検証は全体の課題として `spec/TODO.md` にある)
14//! - セッション再開・再ネゴシエーション・圧縮・クライアント証明書は無し
15//!   (CertificateRequest には空の Certificate を返す)
16//!
17//! 入出力は `embedded_io` の Read/Write の上に作り、ホスト試験では偽のサーバーと
18//! メモリ上でハンドシェイクさせて確かめる(`tests/src/test_tls12.rs`)。
19
20extern 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
42/// 1 レコードの平文の上限(RFC 5246 6.2.1)。
43const MAX_FRAGMENT: usize = 16384;
44
45/// ハッシュ関数(PRF とハンドシェイクの要約に使う)。
46#[derive(Debug, Clone, Copy, PartialEq)]
47pub enum HashAlg {
48    Sha256,
49    Sha384,
50}
51
52/// 対応する暗号スイート。
53#[derive(Debug, Clone, Copy, PartialEq)]
54pub struct Suite {
55    pub id: u16,
56    pub key_len: usize,
57    pub hash: HashAlg,
58}
59
60/// ClientHello で申し出る順(AES-128 を先に。どれも ECDHE + GCM)。
61pub const SUITES: [Suite; 4] = [
62    Suite { id: 0xC02B, key_len: 16, hash: HashAlg::Sha256 }, // ECDHE_ECDSA_AES_128_GCM_SHA256
63    Suite { id: 0xC02F, key_len: 16, hash: HashAlg::Sha256 }, // ECDHE_RSA_AES_128_GCM_SHA256
64    Suite { id: 0xC02C, key_len: 32, hash: HashAlg::Sha384 }, // ECDHE_ECDSA_AES_256_GCM_SHA384
65    Suite { id: 0xC030, key_len: 32, hash: HashAlg::Sha384 }, // ECDHE_RSA_AES_256_GCM_SHA384
66];
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    /// 下層(TCP)の読み書き失敗、または途中で切断された。
75    Io,
76    /// 相手から警告(level, description)が届いた。
77    Alert(u8, u8),
78    /// 形式・手順の誤り。
79    Protocol(&'static str),
80    /// 復号・認証タグ・Finished の照合に失敗した。
81    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
124/// TLS 1.2 の PRF(RFC 5246 5 節の P_hash)。
125pub 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    // A(1) = HMAC(secret, label + seed)
128    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
141/// 鍵スケジュールが約 1KB あるので箱に入れる(カーネルのスタックを使わない)。
142enum Aead {
143    A128(alloc::boxed::Box<Aes128Gcm>),
144    A256(alloc::boxed::Box<Aes256Gcm>),
145}
146
147/// 一方向のレコード暗号(AES-GCM。RFC 5288)。nonce = 暗黙部 4 バイト + 明示部 8 バイト(= 通番)。
148pub 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    /// 平文を暗号化してレコード全体(ヘッダ込み)を返す。
176    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    /// レコードの本体(明示 nonce + 暗号文 + タグ)を復号する。
200    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
221/// ハンドシェイクメッセージ(種別 + 3 バイト長 + 本体)。
222pub 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
236/// ClientHello(ハンドシェイクメッセージ全体)。
237pub 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); // session_id なし
242    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]); // 圧縮なし
247    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]); // supported_groups: secp256r1
258    push_ext(&mut ext, 0x000b, &[1, 0]); // ec_point_formats: uncompressed
259    // signature_algorithms: ecdsa_secp256r1_sha256, rsa_pss_rsae_sha256/384/512,
260    // rsa_pkcs1_sha256/384/512, ecdsa_secp384r1_sha384, rsa_pkcs1_sha1
261    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]); // renegotiation_info(空。RFC 5746)
269    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
274/// ServerHello の本体から (server_random, 暗号スイート) を読む。
275pub 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
291/// ServerKeyExchange(ECDHE)の本体からサーバーの公開鍵(SEC1 非圧縮)を読む。署名は見ない。
292pub 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
302/// 鍵の導出結果。
303pub 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
311/// premaster → master secret → 鍵ブロック(RFC 5246 8.1 / 6.3)。
312pub 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
331/// Finished の verify_data(12 バイト)。`label` は b"client finished" / b"server finished"。
332pub 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
336/// TLS 1.2 の接続。ハンドシェイク後は `embedded_io` の Read/Write として使う。
337pub 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    /// ハンドシェイクまで済ませた接続を返す。
350    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                // CertificateStatus 等、要求していないものは読み飛ばす(記録には含める)。
385                _ => {}
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            // クライアント証明書は持たない: 空の Certificate を返す。
398            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        // サーバーの ChangeCipherSpec を待つ(その前に NewSessionTicket が来ることがある)。
413        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    /// 平文を(必要なら暗号化して)レコードとして送る。
438    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    /// レコードを 1 個読み、(種別, 平文) を返す。警告は `Alert` として返す。
456    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    /// ハンドシェイクメッセージを 1 個取り出す(レコードをまたぐもの・1 レコードに複数あるものに対応)。
487    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    /// close_notify を送る(失敗は無視)。
506    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                // 再ネゴシエーション要求等は無視する。
527                Ok(_) => {}
528                // close_notify と、相手が閉じたことは終端として扱う。
529                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}