Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

pem-rfc7468: a lone CR before -----BEGIN is refused as Error::Preamble, so a CR-terminated multi-certificate PEM fails load_pem_chain (RFC 7468 eol = CRLF / CR / LF)

Đang mở Phù hợp với người mới
#2,486 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@choksi2212 đang làm issue này rồi.

Từ ngày 24/10/2026.

  • #2488 của @choksi2212 — đang mở

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
77/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
rust
Lĩnh vực
backend, security

Hướng nghiên cứu

Bắt đầu với strip_preamble của pem-rfc7468 trong src/grammar.rs và so sánh cách xử lý ranh giới của nó với các helper eol có xử lý CR ở đó. Thêm hoặc điều chỉnh một trường hợp hồi quy cho hai chứng chỉ PEM được phân tách bằng các ký tự xuống dòng CR đơn, sử dụng cách tái hiện được mô tả trong issue. Hoàn tất khi chuỗi chứng chỉ tải được cả hai chứng chỉ và giải mã trực tiếp chấp nhận thông điệp thứ hai sau một CR đơn.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Hi,

Details, the source lines, and a self-contained reproduction are below.

Versions pinned
Thing Pin
pem-rfc7468 1.0.0, the newest release (2026-10-20), .crate sha256 a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9
x509-cert 0.3.0, the newest release, 105ef4642d9cb137ef83d623d0e4bf08b8adf69e9918ca904a174adb6d3d038b, feature pem; over der 0.8.2 and base64ct 1.8.3
the input two v3 certificates assembled in harness/src/main.rs octet by octet, base64 and PEM written there too, in RFC 7468's strict form (64-character lines)
toolchain rustc 1.98.0 (the repository's rust-toolchain.toml)

The checksums are the ones in harness/Cargo.lock.

The rule

RFC 7468 §2: "Data before the encapsulation boundaries are permitted, and
parsers MUST NOT malfunction when processing such data. Furthermore, parsers
SHOULD ignore whitespace and other non-base64 characters and MUST handle
different newline conventions." "Files MAY contain multiple textual encoding instances. This
is used, for example, when a file contains several certificates."
§3's grammar: eol = CRLF / CR / LF, and the strict form every
generator SHOULD emit is stricttextualmsg = preeb eol strictbase64text posteb eol, so a lone CR is a conforming line end in every
figure, and two strict messages written one after the other put the second
-----BEGIN straight after the first's eol. The lax grammar names CR
before the boundary outright: laxtextualmsg = *W preeb, with
W = WSP / CR / LF / %x0B / %x0C.

What the code does

strip_preamble returns the input at once when it starts with
-----BEGIN ; otherwise it walks the bytes and stops only at an LF that the
boundary follows (src/grammar.rs:[email protected], at :71-73).
There is no arm for CR, though the file defines CHAR_CR
(src/grammar.rs:[email protected]) and the two eol helpers below it
accept a lone CR (src/grammar.rs:[email protected],
src/grammar.rs:[email protected]). With no LF at all, it ends at
Err(Error::Preamble) (:80), whose message reads "PEM preamble contains
invalid data (NUL byte)" (src/error.rs:[email protected]) — no NUL is
present. Every decode goes through it
(src/decoder.rs:[email protected]).

The base64 body is not the fault: base64ct trims a lone CR as a line end
(src/decoder.rs:[email protected], :517-519), which is why one
certificate decodes with any line end.

Certificate::load_pem_chain strips the input's trailing CR and LF octets,
then cuts it after each -----END CERTIFICATE----- and hands each piece to
from_pem (src/certificate.rs:[email protected], at :395-408 and
:410-420). The second piece therefore starts with the first message's last
eol: \n-----BEGIN and \r\n-----BEGIN pass strip_preamble; \r-----BEGIN
does not.

What repro.sh shows
Key LF CRLF lone CR RFC 7468
load_pem_chain.one.* (control) Ok(1) Ok(1) Ok(1) read
load_pem_chain.two.* Ok(2), same octets Ok(2), same octets Err read both
decode_vec.after-eol.*: the second message after the first's eol Ok(CERTIFICATE) Ok(CERTIFICATE) Err(Preamble) read
decode_vec.after-text.*: after a line of text, chain + eol Ok(CERTIFICATE) Ok(CERTIFICATE) Err(Preamble) read ("MUST NOT malfunction")

same-octets says each decoded certificate re-encodes to the DER the
harness wrote. The info.* lines print x509-cert's error for the refused
chain; they are not part of the claim.

Severity, and what this does not claim

Conformance. Lone-CR line ends are rare (classic Mac OS text), and a single
certificate is read. The failure is a refusal, not an acceptance, so no
security property is claimed. decode_vec shows the Error::Preamble directly; through
load_pem_chain the run checks only that the chain is refused, and prints
the error.

Affected versions

pem-rfc7468 1.0.0 (newest), through x509-cert 0.3.0 (newest). Earlier
releases were not run. The ask: accept a
lone CR before the pre-encapsulation boundary, as the grammar's eol does.

The path
flowchart TD
  in["cert 1 + cert 2, every eol = CR<br/>(RFC 7468 3: eol = CRLF / CR / LF)"]
  in --> chain["Certificate::load_pem_chain<br/>certificate.rs:380-424"]
  chain --> cut["cut after each -----END CERTIFICATE-----<br/>certificate.rs:410-420"]
  cut --> p1["piece 1: -----BEGIN ... END-----"]
  cut --> p2["piece 2: CR -----BEGIN ... END-----"]
  p1 --> sp1["strip_preamble: starts with -----BEGIN<br/>grammar.rs:62-64"]
  sp1 --> ok1["Certificate 1 decoded<br/>(base64ct trims a lone CR)"]
  p2 --> sp2["strip_preamble: stops only at LF + -----BEGIN<br/>grammar.rs:66-78"]
  sp2 --> pre["no LF anywhere: Err(Preamble)<br/>grammar.rs:80"]
  pre --> fail["load_pem_chain: Err, the whole chain lost"]
  lf["LF or CRLF: piece 2 starts LF -----BEGIN<br/>Ok(2)"]
  classDef bad fill:#fde,stroke:#b35
  classDef good fill:#def,stroke:#37b
  class fail bad
  class lf good
Reproduction script (self-contained)

Save it as repro.sh and run bash repro.sh. It writes the files it needs into a new temporary directory and runs the check there; it exits 0 when every observation matches this report. The script is yours to use under Apache-2.0 OR MIT.

#!/usr/bin/env bash
# SPDX-FileCopyrightText: Protoworks Group (Pty) Ltd
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
# Self-contained reproduction (UP-PEMRFC7468-001). It writes the files below into a new
# temporary directory and runs repro.sh there; nothing outside that
# directory is written. Run it with: bash this-file.sh
set -euo pipefail
dir=$(mktemp -d "${TMPDIR:-/tmp}/repro.XXXXXX")
echo "files written to $dir"
cat >"$dir/rust-toolchain.toml" <<'__REPRO_FILE_1__'
[toolchain]
channel = "1.98.0"
__REPRO_FILE_1__
mkdir -p "$dir/harness"
cat >"$dir/harness/Cargo.lock" <<'__REPRO_FILE_2__'
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "base64ct"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"

[[package]]
name = "const-oid"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"

[[package]]
name = "der"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a878c850e9e421b20262e9b41f9c860e4785fa07541c266b62ff9d1ef998a80a"
dependencies = [
 "const-oid",
 "der_derive",
 "flagset",
 "pem-rfc7468",
 "zeroize",
]

[[package]]
name = "der_derive"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59600e2c2d636fde9b65e99cc6445ac770c63d3628195ff39932b8d6d7409903"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "flagset"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe"

[[package]]
name = "pem-rfc7468"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9"
dependencies = [
 "base64ct",
]

[[package]]
name = "proc-macro2"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
dependencies = [
 "unicode-ident",
]

[[package]]
name = "quote"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "spki"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef958a98b9d5da290cfc78946e9f3e61e1e62a18db0d92cac0b83cc161491a9"
dependencies = [
 "base64ct",
 "der",
]

[[package]]
name = "syn"
version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-ident",
]

[[package]]
name = "unicode-ident"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"

[[package]]
name = "up-pemrfc7468-001"
version = "0.0.0"
dependencies = [
 "pem-rfc7468",
 "x509-cert",
]

[[package]]
name = "x509-cert"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "105ef4642d9cb137ef83d623d0e4bf08b8adf69e9918ca904a174adb6d3d038b"
dependencies = [
 "const-oid",
 "der",
 "spki",
]

[[package]]
name = "zeroize"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879"
__REPRO_FILE_2__
mkdir -p "$dir/harness"
cat >"$dir/harness/Cargo.toml" <<'__REPRO_FILE_3__'
# SPDX-FileCopyrightText: Protoworks Group (Pty) Ltd
# SPDX-License-Identifier: Apache-2.0 OR MIT
#

# UP-PEMRFC7468-001's harness: pem-rfc7468 1.0.0 directly and under
# x509-cert 0.3.0's load_pem_chain (the newest of each). The harness writes
# the PEM text itself, so neither crate under test produces its own input.
[package]
name = "up-pemrfc7468-001"
version = "0.0.0"
edition = "2021"
publish = false

[dependencies]
pem-rfc7468 = { version = "=1.0.0", features = ["alloc"] }
x509-cert = { version = "=0.3.0", default-features = false, features = ["pem"] }

[workspace]
__REPRO_FILE_3__
mkdir -p "$dir/harness/src"
cat >"$dir/harness/src/main.rs" <<'__REPRO_FILE_4__'
// SPDX-FileCopyrightText: Protoworks Group (Pty) Ltd
// SPDX-License-Identifier: Apache-2.0 OR MIT
//

//! UP-PEMRFC7468-001: two PEM certificates, one after the other, with every
//! line ended by LF, by CRLF and by a lone CR (RFC 7468 §3: `eol = CRLF / CR
//! / LF`), through pem-rfc7468 1.0.0 directly and through x509-cert 0.3.0's
//! `Certificate::load_pem_chain`. The certificates are assembled and the PEM
//! text written here, so neither crate produces its own input. Prints
//! `OBS key=value`.

use pem_rfc7468::decode_vec;
use x509_cert::der::Encode as _;
use x509_cert::Certificate;

fn tlv(tag: u8, value: &[u8]) -> Vec<u8> {
    let mut out = vec![tag];
    let n = value.len();
    if n < 0x80 {
        out.push(n as u8);
    } else if n <= 0xff {
        out.extend([0x81, n as u8]);
    } else {
        out.extend([0x82, (n >> 8) as u8, n as u8]);
    }
    out.extend_from_slice(value);
    out
}

fn seq(parts: &[Vec<u8>]) -> Vec<u8> {
    tlv(0x30, &parts.concat())
}

/// X.690 §8.19 contents octets of an OID whose arcs after the first two are
/// each below 2^14.
fn oid(arcs: &[u32]) -> Vec<u8> {
    let mut out = vec![(arcs[0] * 40 + arcs[1]) as u8];
    for &arc in &arcs[2..] {
        if arc >= 0x80 {
            out.push(0x80 | (arc >> 7) as u8);
        }
        out.push((arc & 0x7f) as u8);
    }
    tlv(0x06, &out)
}

/// A v3 certificate with serial `serial`; nothing in it is signed.
fn certificate(serial: u8) -> Vec<u8> {
    let ecdsa_sha256 = seq(&[oid(&[1, 2, 840, 10045, 4, 3, 2])]);
    let name = seq(&[tlv(0x31, &seq(&[oid(&[2, 5, 4, 3]), tlv(0x0c, b"up-pemrfc7468-001")]))]);
    let validity = seq(&[tlv(0x17, b"250101000000Z"), tlv(0x17, b"350101000000Z")]);
    let mut point = vec![0x00, 0x04];
    point.extend([0x22; 64]);
    let spki = seq(&[
        seq(&[oid(&[1, 2, 840, 10045, 2, 1]), oid(&[1, 2, 840, 10045, 3, 1, 7])]),
        tlv(0x03, &point),
    ]);
    let tbs = seq(&[
        tlv(0xa0, &tlv(0x02, &[0x02])),
        tlv(0x02, &[serial]),
        ecdsa_sha256.clone(),
        name.clone(),
        validity,
        name,
        spki,
    ]);
    seq(&[tbs, ecdsa_sha256, tlv(0x03, &[0x00, 0x01, 0x02, 0x03])])
}

/// RFC 4648 §4 base64, written here.
fn base64(data: &[u8]) -> String {
    const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    let mut out = String::new();
    for chunk in data.chunks(3) {
        let b = [chunk[0], *chunk.get(1).unwrap_or(&0), *chunk.get(2).unwrap_or(&0)];
        let n = (u32::from(b[0]) << 16) | (u32::from(b[1]) << 8) | u32::from(b[2]);
        for i in 0..4 {
            if i <= chunk.len() {
                out.push(ALPHABET[((n >> (18 - 6 * i)) & 0x3f) as usize] as char);
            } else {
                out.push('=');
            }
        }
    }
    out
}

/// RFC 7468 Figure 3 (strict): `preeb eol`, 64-character lines, `posteb eol`,
/// with `eol` the given line end.
fn pem(der: &[u8], eol: &str) -> String {
    let text = base64(der);
    let mut out = format!("-----BEGIN CERTIFICATE-----{eol}");
    for line in text.as_bytes().chunks(64) {
        out.push_str(std::str::from_utf8(line).expect("ascii"));
        out.push_str(eol);
    }
    out.push_str(&format!("-----END CERTIFICATE-----{eol}"));
    out
}

fn obs(key: &str, value: impl std::fmt::Display) {
    println!("OBS {key}={value}");
}

fn main() {
    let first = certificate(1);
    let second = certificate(2);

    for (name, eol) in [("LF", "\n"), ("CRLF", "\r\n"), ("CR", "\r")] {
        let one = pem(&first, eol);
        let two = format!("{one}{}", pem(&second, eol));

        // x509-cert 0.3.0: one certificate, then the chain of two.
        match Certificate::load_pem_chain(one.as_bytes()) {
            Ok(certs) => obs(&format!("load_pem_chain.one.{name}"), format!("Ok({})", certs.len())),
            Err(e) => {
                obs(&format!("load_pem_chain.one.{name}"), "Err");
                obs(&format!("info.load_pem_chain.one.{name}.error"), e);
            }
        }
        match Certificate::load_pem_chain(two.as_bytes()) {
            Ok(certs) => {
                obs(&format!("load_pem_chain.two.{name}"), format!("Ok({})", certs.len()));
                let same = certs.len() == 2
                    && certs[0].to_der().map(|d| d == first).unwrap_or(false)
                    && certs[1].to_der().map(|d| d == second).unwrap_or(false);
                obs(&format!("load_pem_chain.two.{name}.same-octets"), same);
            }
            Err(e) => {
                obs(&format!("load_pem_chain.two.{name}"), "Err");
                obs(&format!("info.load_pem_chain.two.{name}.error"), e);
            }
        }

        // pem-rfc7468 1.0.0: the second message as load_pem_chain hands it
        // over (the first message's last eol in front), and with a line of
        // explanatory text in front.
        for (what, preamble) in [("after-eol", eol.to_owned()), ("after-text", format!("chain{eol}"))] {
            let input = format!("{preamble}{}", pem(&second, eol));
            let got = match decode_vec(input.as_bytes()) {
                Ok((label, der)) if der == second => format!("Ok({label})"),
                Ok((label, _)) => format!("Ok({label}, other octets)"),
                Err(e) => format!("Err({e:?})"),
            };
            obs(&format!("decode_vec.{what}.{name}"), got);
        }
    }
}
__REPRO_FILE_4__
cat >"$dir/repro.sh" <<'__REPRO_FILE_5__'
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Protoworks Group (Pty) Ltd
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
set -euo pipefail

# repro.sh — UP-PEMRFC7468-001: pem-rfc7468 1.0.0 (the newest release) finds
# a pre-encapsulation boundary only at the start of its input or after an
# LF, so when every line ends in a lone CR (RFC 7468 §3: `eol = CRLF / CR /
# LF`) x509-cert 0.3.0's Certificate::load_pem_chain reads one certificate
# and refuses a chain of two it reads with LF or CRLF. A defensive check
# over certificates and PEM text the harness writes itself.
#
#   ./repro.sh
#
# What it does: builds harness/ (locked by harness/Cargo.lock) with the
# toolchain rust-toolchain.toml pins, runs it, and compares each
# `OBS key=value` with EXPECT, the claim table of the report. Lines named
# info.* are printed for the reader and not checked.
#
# Network: cargo's fetch of the crates harness/Cargo.lock pins. Nothing else.
#
# Exit status: 0 when every check holds (the defect is shown); otherwise the
# number of checks that disagreed; 2 if the harness could not be built or run.
#
# Dependencies: bash, awk, cargo and rustup (1.98.0).

here=$(cd "$(dirname "$0")" && pwd)
cd "$here"

fail=0
note() { echo "repro: $*"; }
check() {  # check <label> <want> <got>
  if [[ "$2" == "$3" ]]; then
    printf '  ok   %-60s %s\n' "$1" "$3"
  else
    printf '  FAIL %-60s got %s, want %s\n' "$1" "$3" "$2"
    fail=$((fail + 1))
  fi
}

if ! command -v cargo >/dev/null 2>&1; then
  note "cargo is not installed; cannot run"
  exit 2
fi
target=$(mktemp -d "${TMPDIR:-/tmp}/up-ev.XXXXXX")
trap 'rm -rf "$target"' EXIT

# The toolchain is the one the repository's rust-toolchain.toml pins.
rustc_version=$(cd "$here/harness" && rustc --version)
note "toolchain: $rustc_version"
check "rustc is the pinned 1.98.0" "rustc 1.98.0" "$(cut -d' ' -f1-2 <<<"$rustc_version")"

run_harness() {  # run_harness -> the harness's stdout
  (cd "$here/harness" && CARGO_TARGET_DIR="$target" cargo run --locked --quiet --release)
}

compare() {  # compare <label> <harness output> ; reads key=value lines on stdin
  local label="$1" out="$2" key want got
  while IFS='=' read -r key want; do
    [[ -z "$key" || "$key" == \#* ]] && continue
    got=$(awk -v k="OBS ${key}=" 'index($0, k) == 1 { print substr($0, length(k) + 1); exit }' <<<"$out")
    [[ -n "$got" ]] || got="(not printed)"
    check "$label: $key" "$want" "$got"
  done
}

finish() {  # finish <id>
  echo
  if [[ "$fail" -eq 0 ]]; then
    note "all checks held: $1 is shown as the report states it"
    exit 0
  fi
  note "$fail checks disagreed with the claim"
  exit "$fail"
}

note "building and running harness/ (pem-rfc7468 1.0.0, x509-cert 0.3.0)"
out=$(run_harness) || { note "the harness did not build or run"; exit 2; }
printf '%s\n' "$out" | sed 's/^/    /'

# The controls: LF and CRLF read the chain, and one certificate is read
# with every line end, so the base64 body with lone CRs is not the fault.
compare control "$out" <<'EXPECT'
load_pem_chain.one.LF=Ok(1)
load_pem_chain.one.CRLF=Ok(1)
load_pem_chain.one.CR=Ok(1)
load_pem_chain.two.LF=Ok(2)
load_pem_chain.two.LF.same-octets=true
load_pem_chain.two.CRLF=Ok(2)
load_pem_chain.two.CRLF.same-octets=true
decode_vec.after-eol.LF=Ok(CERTIFICATE)
decode_vec.after-eol.CRLF=Ok(CERTIFICATE)
decode_vec.after-text.LF=Ok(CERTIFICATE)
decode_vec.after-text.CRLF=Ok(CERTIFICATE)
EXPECT

compare claim "$out" <<'EXPECT'
load_pem_chain.two.CR=Err
decode_vec.after-eol.CR=Err(Preamble)
decode_vec.after-text.CR=Err(Preamble)
EXPECT

finish UP-PEMRFC7468-001
__REPRO_FILE_5__
chmod +x "$dir/repro.sh"
cd "$dir" && ./repro.sh
Recorded run
date: 2026-10-21T10:16:31Z
arch: Darwin arm64
tools: bash 5.3.20(1)-release; git version 2.56.0; docker client 29.9.0; shellcheck 0.11.0

repro: toolchain: rustc 1.98.0 (88d9e12ae 2026-08-18)
  ok   rustc is the pinned 1.98.0                                   rustc 1.98.0
repro: building and running harness/ (pem-rfc7468 1.0.0, x509-cert 0.3.0)
    OBS load_pem_chain.one.LF=Ok(1)
    OBS load_pem_chain.two.LF=Ok(2)
    OBS load_pem_chain.two.LF.same-octets=true
    OBS decode_vec.after-eol.LF=Ok(CERTIFICATE)
    OBS decode_vec.after-text.LF=Ok(CERTIFICATE)
    OBS load_pem_chain.one.CRLF=Ok(1)
    OBS load_pem_chain.two.CRLF=Ok(2)
    OBS load_pem_chain.two.CRLF.same-octets=true
    OBS decode_vec.after-eol.CRLF=Ok(CERTIFICATE)
    OBS decode_vec.after-text.CRLF=Ok(CERTIFICATE)
    OBS load_pem_chain.one.CR=Ok(1)
    OBS load_pem_chain.two.CR=Err
    OBS info.load_pem_chain.two.CR.error=PEM error: PEM preamble contains invalid data (NUL byte)
    OBS decode_vec.after-eol.CR=Err(Preamble)
    OBS decode_vec.after-text.CR=Err(Preamble)
  ok   control: load_pem_chain.one.LF                               Ok(1)
  ok   control: load_pem_chain.one.CRLF                             Ok(1)
  ok   control: load_pem_chain.one.CR                               Ok(1)
  ok   control: load_pem_chain.two.LF                               Ok(2)
  ok   control: load_pem_chain.two.LF.same-octets                   true
  ok   control: load_pem_chain.two.CRLF                             Ok(2)
  ok   control: load_pem_chain.two.CRLF.same-octets                 true
  ok   control: decode_vec.after-eol.LF                             Ok(CERTIFICATE)
  ok   control: decode_vec.after-eol.CRLF                           Ok(CERTIFICATE)
  ok   control: decode_vec.after-text.LF                            Ok(CERTIFICATE)
  ok   control: decode_vec.after-text.CRLF                          Ok(CERTIFICATE)
  ok   claim: load_pem_chain.two.CR                                 Err
  ok   claim: decode_vec.after-eol.CR                               Err(Preamble)
  ok   claim: decode_vec.after-text.CR                              Err(Preamble)

repro: all checks held: UP-PEMRFC7468-001 is shown as the report states it

exit: 0
Ngôn ngữ chính
Rust
Star
344
Fork
196
Merge trung bình
1 ngày 17 giờ
Pull request đã merge (30 ngày)
24

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của RustCrypto/formats

Tất cả issue của RustCrypto/formats

Issue tương tự

Thêm issue về Rust

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.