1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
45// This file contains code that was copied from the ring crate which is under
6// the ISC license, reproduced below:
78// Copyright 2015-2017 Brian Smith.
910// Permission to use, copy, modify, and/or distribute this software for any
11// purpose with or without fee is hereby granted, provided that the above
12// copyright notice and this permission notice appear in all copies.
1314// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
15// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
17// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2122use crate::Result;
23use nss::{ec::Curve, ec::PublicKey, pbkdf2::HashAlgorithm};
2425/// A signature verification algorithm.
26pub struct VerificationAlgorithm {
27 curve: Curve,
28 digest_alg: HashAlgorithm,
29}
3031pub static ECDSA_P256_SHA256: VerificationAlgorithm = VerificationAlgorithm {
32 curve: Curve::P256,
33 digest_alg: HashAlgorithm::SHA256,
34};
3536pub static ECDSA_P384_SHA384: VerificationAlgorithm = VerificationAlgorithm {
37 curve: Curve::P384,
38 digest_alg: HashAlgorithm::SHA384,
39};
4041/// An unparsed public key for signature operations.
42pub struct UnparsedPublicKey<'a> {
43 alg: &'static VerificationAlgorithm,
44 bytes: &'a [u8],
45}
4647impl<'a> UnparsedPublicKey<'a> {
48pub fn new(algorithm: &'static VerificationAlgorithm, bytes: &'a [u8]) -> Self {
49Self {
50 alg: algorithm,
51 bytes,
52 }
53 }
5455pub fn verify(&self, message: &[u8], signature: &[u8]) -> Result<()> {
56let pub_key = PublicKey::from_bytes(self.alg.curve, self.bytes)?;
57Ok(pub_key.verify(message, signature, self.alg.digest_alg)?)
58 }
5960pub fn algorithm(&self) -> &'static VerificationAlgorithm {
61self.alg
62 }
6364pub fn bytes(&self) -> &'a [u8] {
65self.bytes
66 }
67}
6869#[cfg(test)]
70mod tests {
71use super::*;
72use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
73use nss::ensure_initialized;
7475#[test]
76fn test_ecdsa_p384_sha384_verify() {
77 ensure_initialized();
78// Test generated with JS DOM's WebCrypto.
79let pub_key_bytes = URL_SAFE_NO_PAD.decode(
80"BMZj_xHOfLQn5DIEQcYUkyASDWo8O30gWdkWXHHHWN5owKhGWplYHEb4PLf3DkFTg_smprr-ApdULy3NV10x8IZ0EfVaUZdXvTquH1kiw2PxD7fhqiozMXUaSuZI5KBE6w",
81 ).unwrap();
82let message = URL_SAFE_NO_PAD.decode(
83"F9MQDmEEdvOfm-NkCRrXqG-aVA9kq0xqtjvtWLndmmt6bO2gfLE2CVDDLzJYds0n88uz27c5JkzdsLpm5HP3aLFgD8bgnGm-EgdBpm99CRiIm7mAMbb0-NRAyUxeoGmdgJPVQLWFNoHRwzKV2wZ0Bk-Bq7jkeDHmDfnx-CJKVMQ",
84 )
85 .unwrap();
86let signature = URL_SAFE_NO_PAD.decode(
87"XLZmtJweW4qx0u0l6EpfmB5z-S-CNj4mrl9d7U0MuftdNPhmlNacV4AKR-i4uNn0TUIycU7GsfIjIqxuiL9WdAnfq_KH_SJ95mduqXgWNKlyt8JgMLd4h-jKOllh4erh",
88 )
89 .unwrap();
90let public_key =
91crate::signature::UnparsedPublicKey::new(&ECDSA_P384_SHA384, &pub_key_bytes);
9293// Failure case: Wrong key algorithm.
94let public_key_wrong_alg =
95crate::signature::UnparsedPublicKey::new(&ECDSA_P256_SHA256, &pub_key_bytes);
96assert!(public_key_wrong_alg.verify(&message, &signature).is_err());
9798// Failure case: Add garbage to signature.
99let mut garbage_signature = signature.clone();
100 garbage_signature.push(42);
101assert!(public_key.verify(&message, &garbage_signature).is_err());
102103// Failure case: Flip a bit in message.
104let mut garbage_message = message.clone();
105 garbage_message[42] = 42;
106assert!(public_key.verify(&garbage_message, &signature).is_err());
107108// Happy case.
109assert!(public_key.verify(&message, &signature).is_ok());
110 }
111}