|
| 1 | +use super::CryptoError; |
| 2 | + |
| 3 | +pub const TAG_INTEGER: u8 = 0x02; |
| 4 | +pub const TAG_BIT_STRING: u8 = 0x03; |
| 5 | +#[cfg(all(test, feature = "crypto_nss"))] |
| 6 | +pub const TAG_OCTET_STRING: u8 = 0x04; |
| 7 | +pub const TAG_NULL: u8 = 0x05; |
| 8 | +pub const TAG_OBJECT_ID: u8 = 0x06; |
| 9 | +pub const TAG_SEQUENCE: u8 = 0x30; |
| 10 | + |
| 11 | +// Object identifiers in DER tag-length-value form |
| 12 | +pub const OID_EC_PUBLIC_KEY_BYTES: &[u8] = &[ |
| 13 | + /* RFC 5480 (id-ecPublicKey) */ |
| 14 | + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, |
| 15 | +]; |
| 16 | +pub const OID_SECP256R1_BYTES: &[u8] = &[ |
| 17 | + /* RFC 5480 (secp256r1) */ |
| 18 | + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, |
| 19 | +]; |
| 20 | +pub const OID_ED25519_BYTES: &[u8] = &[/* RFC 8410 (id-ed25519) */ 0x2b, 0x65, 0x70]; |
| 21 | +pub const OID_RS256_BYTES: &[u8] = &[ |
| 22 | + /* RFC 4055 (sha256WithRSAEncryption) */ |
| 23 | + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, |
| 24 | +]; |
| 25 | + |
| 26 | +pub type Result<T> = std::result::Result<T, CryptoError>; |
| 27 | + |
| 28 | +const MAX_TAG_AND_LENGTH_BYTES: usize = 4; |
| 29 | +fn write_tag_and_length(out: &mut Vec<u8>, tag: u8, len: usize) -> Result<()> { |
| 30 | + if len > 0xFFFF { |
| 31 | + return Err(CryptoError::LibraryFailure); |
| 32 | + } |
| 33 | + out.push(tag); |
| 34 | + if len > 0xFF { |
| 35 | + out.push(0x82); |
| 36 | + out.push((len >> 8) as u8); |
| 37 | + out.push(len as u8); |
| 38 | + } else if len > 0x7F { |
| 39 | + out.push(0x81); |
| 40 | + out.push(len as u8); |
| 41 | + } else { |
| 42 | + out.push(len as u8); |
| 43 | + } |
| 44 | + Ok(()) |
| 45 | +} |
| 46 | + |
| 47 | +pub fn integer(val: &[u8]) -> Result<Vec<u8>> { |
| 48 | + // trim leading zeros, leaving a single zero if the input is the zero vector. |
| 49 | + let mut val = val; |
| 50 | + while val.len() > 1 && val[0] == 0 { |
| 51 | + val = &val[1..]; |
| 52 | + } |
| 53 | + |
| 54 | + let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + 1 + val.len()); |
| 55 | + if !val.is_empty() && val[0] & 0x80 != 0 { |
| 56 | + // needs zero prefix |
| 57 | + write_tag_and_length(&mut out, TAG_INTEGER, 1 + val.len())?; |
| 58 | + out.push(0x00); |
| 59 | + out.extend_from_slice(val); |
| 60 | + } else { |
| 61 | + write_tag_and_length(&mut out, TAG_INTEGER, val.len())?; |
| 62 | + out.extend_from_slice(val); |
| 63 | + } |
| 64 | + Ok(out) |
| 65 | +} |
| 66 | + |
| 67 | +pub fn bit_string(val: &[u8]) -> Result<Vec<u8>> { |
| 68 | + let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + 1 + val.len()); |
| 69 | + write_tag_and_length(&mut out, TAG_BIT_STRING, 1 + val.len())?; |
| 70 | + out.push(0x00); // trailing bits aren't supported |
| 71 | + out.extend_from_slice(val); |
| 72 | + Ok(out) |
| 73 | +} |
| 74 | + |
| 75 | +pub fn null() -> Result<Vec<u8>> { |
| 76 | + let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES); |
| 77 | + write_tag_and_length(&mut out, TAG_NULL, 0)?; |
| 78 | + Ok(out) |
| 79 | +} |
| 80 | + |
| 81 | +pub fn object_id(val: &[u8]) -> Result<Vec<u8>> { |
| 82 | + let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + val.len()); |
| 83 | + write_tag_and_length(&mut out, TAG_OBJECT_ID, val.len())?; |
| 84 | + out.extend_from_slice(val); |
| 85 | + Ok(out) |
| 86 | +} |
| 87 | + |
| 88 | +pub fn sequence(items: &[&[u8]]) -> Result<Vec<u8>> { |
| 89 | + let len = items.iter().map(|i| i.len()).sum(); |
| 90 | + let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + len); |
| 91 | + write_tag_and_length(&mut out, TAG_SEQUENCE, len)?; |
| 92 | + for item in items { |
| 93 | + out.extend_from_slice(item); |
| 94 | + } |
| 95 | + Ok(out) |
| 96 | +} |
| 97 | + |
| 98 | +#[cfg(all(test, feature = "crypto_nss"))] |
| 99 | +pub fn octet_string(val: &[u8]) -> Result<Vec<u8>> { |
| 100 | + let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + val.len()); |
| 101 | + write_tag_and_length(&mut out, TAG_OCTET_STRING, val.len())?; |
| 102 | + out.extend_from_slice(val); |
| 103 | + Ok(out) |
| 104 | +} |
| 105 | + |
| 106 | +#[cfg(all(test, feature = "crypto_nss"))] |
| 107 | +pub fn context_specific_explicit_tag(tag: u8, content: &[u8]) -> Result<Vec<u8>> { |
| 108 | + let mut out = Vec::with_capacity(MAX_TAG_AND_LENGTH_BYTES + content.len()); |
| 109 | + write_tag_and_length(&mut out, 0xa0 + tag, content.len())?; |
| 110 | + out.extend_from_slice(content); |
| 111 | + Ok(out) |
| 112 | +} |
| 113 | + |
| 114 | +// Given "tag || len || value || rest" where tag and len are of length one, len is in [0, 127], |
| 115 | +// and value is of length len, returns (value, rest) |
| 116 | +#[cfg(all(test, feature = "crypto_nss"))] |
| 117 | +fn expect_tag_with_short_len(tag: u8, z: &[u8]) -> Result<(&[u8], &[u8])> { |
| 118 | + if z.is_empty() { |
| 119 | + return Err(CryptoError::MalformedInput); |
| 120 | + } |
| 121 | + let (h, z) = z.split_at(1); |
| 122 | + if h[0] != tag || z.is_empty() { |
| 123 | + return Err(CryptoError::MalformedInput); |
| 124 | + } |
| 125 | + let (h, z) = z.split_at(1); |
| 126 | + if h[0] >= 0x80 || h[0] as usize > z.len() { |
| 127 | + return Err(CryptoError::MalformedInput); |
| 128 | + } |
| 129 | + Ok(z.split_at(h[0] as usize)) |
| 130 | +} |
| 131 | + |
| 132 | +// Given a DER encoded RFC 3279 Ecdsa-Sig-Value, |
| 133 | +// Ecdsa-Sig-Value ::= SEQUENCE { |
| 134 | +// r INTEGER, |
| 135 | +// s INTEGER }, |
| 136 | +// with r and s < 2^256, returns a 64 byte array containing |
| 137 | +// r and s encoded as 32 byte zero-padded big endian unsigned |
| 138 | +// integers |
| 139 | +#[cfg(all(test, feature = "crypto_nss"))] |
| 140 | +pub fn read_p256_sig(z: &[u8]) -> Result<Vec<u8>> { |
| 141 | + // Strip the tag and length. |
| 142 | + let (z, rest) = expect_tag_with_short_len(TAG_SEQUENCE, z)?; |
| 143 | + |
| 144 | + // The input should not have any trailing data. |
| 145 | + if !rest.is_empty() { |
| 146 | + return Err(CryptoError::MalformedInput); |
| 147 | + } |
| 148 | + |
| 149 | + let read_u256 = |z| -> Result<(&[u8], &[u8])> { |
| 150 | + let (r, z) = expect_tag_with_short_len(TAG_INTEGER, z)?; |
| 151 | + // We're expecting r < 2^256, so no more than 33 bytes as a signed integer. |
| 152 | + if r.is_empty() || r.len() > 33 { |
| 153 | + return Err(CryptoError::MalformedInput); |
| 154 | + } |
| 155 | + // If it is 33 bytes the leading byte must be zero. |
| 156 | + if r.len() == 33 && r[0] != 0 { |
| 157 | + return Err(CryptoError::MalformedInput); |
| 158 | + } |
| 159 | + // Ensure r is no more than 32 bytes. |
| 160 | + if r.len() == 33 { |
| 161 | + Ok((&r[1..], z)) |
| 162 | + } else { |
| 163 | + Ok((r, z)) |
| 164 | + } |
| 165 | + }; |
| 166 | + |
| 167 | + let (r, z) = read_u256(z)?; |
| 168 | + let (s, z) = read_u256(z)?; |
| 169 | + |
| 170 | + // We should have consumed the entire buffer |
| 171 | + if !z.is_empty() { |
| 172 | + return Err(CryptoError::MalformedInput); |
| 173 | + } |
| 174 | + |
| 175 | + // Left pad each integer with zeros to length 32 and concatenate the results |
| 176 | + let mut out = vec![0u8; 64]; |
| 177 | + { |
| 178 | + let (r_out, s_out) = out.split_at_mut(32); |
| 179 | + r_out[32 - r.len()..].copy_from_slice(r); |
| 180 | + s_out[32 - s.len()..].copy_from_slice(s); |
| 181 | + } |
| 182 | + Ok(out) |
| 183 | +} |
0 commit comments