Coverage Report

Created: 2026-05-18 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/git/checkouts/nss-rs-71e20fe79ef91440/9b94ca3/src/der.rs
Line
Count
Source
1
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4
// option. This file may not be copied, modified, or distributed
5
// except according to those terms.
6
7
use crate::Error;
8
9
pub const TAG_INTEGER: u8 = 0x02;
10
pub const TAG_BIT_STRING: u8 = 0x03;
11
pub const TAG_OCTET_STRING: u8 = 0x04;
12
pub const TAG_NULL: u8 = 0x05;
13
pub const TAG_OBJECT_ID: u8 = 0x06;
14
pub const TAG_SEQUENCE: u8 = 0x30;
15
16
// Object identifiers in DER tag-length-value form
17
pub const OID_EC_PUBLIC_KEY_BYTES: &[u8] = &[
18
    /* RFC 5480 (id-ecPublicKey) */
19
    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
20
];
21
pub const OID_SECP256R1_BYTES: &[u8] = &[
22
    /* RFC 5480 (secp256r1) */
23
    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
24
];
25
pub const OID_ED25519_BYTES: &[u8] = &[/* RFC 8410 (id-ed25519) */ 0x2b, 0x65, 0x70];
26
pub const OID_RS256_BYTES: &[u8] = &[
27
    /* RFC 4055 (sha256WithRSAEncryption) */
28
    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
29
];
30
31
pub const MAX_TAG_AND_LENGTH_BYTES: usize = 4;
32
33
#[expect(clippy::cast_possible_truncation)]
34
0
pub fn write_tag_and_length(out: &mut Vec<u8>, tag: u8, len: usize) -> Result<(), Error> {
35
0
    if len > 0xFFFF {
36
0
        return Err(Error::Internal);
37
0
    }
38
0
    out.push(tag);
39
0
    if len > 0xFF {
40
0
        out.push(0x82);
41
0
        out.push((len >> 8) as u8);
42
0
    } else if len > 0x7F {
43
0
        out.push(0x81);
44
0
    }
45
0
    out.push(len as u8);
46
0
    Ok(())
47
0
}
48
49
0
pub fn integer(val: &[u8]) -> Result<Vec<u8>, Error> {
50
0
    if val.is_empty() {
51
0
        return Err(Error::InvalidInput);
52
0
    }
53
    // trim leading zeros, leaving a single zero if the input is the zero vector.
54
0
    let mut val = val;
55
0
    while val.len() > 1 && val[0] == 0 {
56
0
        val = &val[1..];
57
0
    }
58
0
    let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + 1 + val.len());
59
0
    if val[0] & 0x80 != 0 {
60
        // needs zero prefix
61
0
        write_tag_and_length(&mut out, TAG_INTEGER, 1 + val.len())?;
62
0
        out.push(0x00);
63
    } else {
64
0
        write_tag_and_length(&mut out, TAG_INTEGER, val.len())?;
65
    }
66
0
    out.extend_from_slice(val);
67
0
    Ok(out)
68
0
}
69
70
0
pub fn bit_string(val: &[u8]) -> Result<Vec<u8>, Error> {
71
0
    let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + 1 + val.len());
72
0
    write_tag_and_length(&mut out, TAG_BIT_STRING, 1 + val.len())?;
73
0
    out.push(0x00); // trailing bits aren't supported
74
0
    out.extend_from_slice(val);
75
0
    Ok(out)
76
0
}
77
78
0
pub fn null() -> Result<Vec<u8>, Error> {
79
0
    let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES);
80
0
    write_tag_and_length(&mut out, TAG_NULL, 0)?;
81
0
    Ok(out)
82
0
}
83
84
0
pub fn object_id(val: &[u8]) -> Result<Vec<u8>, Error> {
85
0
    let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + val.len());
86
0
    write_tag_and_length(&mut out, TAG_OBJECT_ID, val.len())?;
87
0
    out.extend_from_slice(val);
88
0
    Ok(out)
89
0
}
90
91
0
pub fn sequence(items: &[&[u8]]) -> Result<Vec<u8>, Error> {
92
0
    let len = items.iter().map(|i| i.len()).sum();
93
0
    let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + len);
94
0
    write_tag_and_length(&mut out, TAG_SEQUENCE, len)?;
95
0
    for item in items {
96
0
        out.extend_from_slice(item);
97
0
    }
98
0
    Ok(out)
99
0
}
100
101
0
pub fn octet_string(val: &[u8]) -> Result<Vec<u8>, Error> {
102
0
    let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + val.len());
103
0
    write_tag_and_length(&mut out, TAG_OCTET_STRING, val.len())?;
104
0
    out.extend_from_slice(val);
105
0
    Ok(out)
106
0
}
107
108
0
pub fn context_specific_explicit_tag(tag: u8, content: &[u8]) -> Result<Vec<u8>, Error> {
109
0
    let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + content.len());
110
0
    write_tag_and_length(&mut out, 0xa0 + tag, content.len())?;
111
0
    out.extend_from_slice(content);
112
0
    Ok(out)
113
0
}
114
115
// Given "tag || len || value || rest" where tag and len are of length one, len is in [0, 127],
116
// and value is of length len, returns (value, rest)
117
0
pub fn expect_tag_with_short_len(tag: u8, z: &[u8]) -> Result<(&[u8], &[u8]), Error> {
118
0
    if z.is_empty() {
119
0
        return Err(Error::InvalidInput);
120
0
    }
121
0
    let (h, z) = z.split_at(1);
122
0
    if h[0] != tag || z.is_empty() {
123
0
        return Err(Error::InvalidInput);
124
0
    }
125
0
    let (h, z) = z.split_at(1);
126
0
    if h[0] >= 0x80 || h[0] as usize > z.len() {
127
0
        return Err(Error::InvalidInput);
128
0
    }
129
0
    Ok(z.split_at(h[0] as usize))
130
0
}