Use upstream jsonwebtoken crate (#4472)

This commit is contained in:
Gerard Guillemas Martos 2024-08-07 13:38:02 +02:00 committed by GitHub
parent 4f3b96334e
commit e60ce36083
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 502 additions and 529 deletions

154
Cargo.lock generated
View file

@ -1333,12 +1333,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "const-oid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "convert_case"
version = "0.4.0"
@ -1616,17 +1610,6 @@ dependencies = [
"uuid",
]
[[package]]
name = "der"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
dependencies = [
"const-oid",
"pem-rfc7468",
"zeroize",
]
[[package]]
name = "deranged"
version = "0.3.11"
@ -1724,7 +1707,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"const-oid",
"crypto-common",
"subtle",
]
@ -3023,7 +3005,7 @@ checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f"
dependencies = [
"base64 0.21.7",
"js-sys",
"pem 3.0.3",
"pem",
"ring 0.17.8",
"serde",
"serde_json",
@ -3072,9 +3054,6 @@ name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
dependencies = [
"spin 0.5.2",
]
[[package]]
name = "lazycell"
@ -3565,23 +3544,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-bigint-dig"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
dependencies = [
"byteorder",
"lazy_static",
"libm",
"num-integer",
"num-iter",
"num-traits",
"rand 0.8.5",
"smallvec",
"zeroize",
]
[[package]]
name = "num-complex"
version = "0.4.5"
@ -3616,17 +3578,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.18"
@ -3920,16 +3871,6 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "pem"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b13fe415cdf3c8e44518e18a7c95a13431d9bdf6d15367d82b23c377fdd441a"
dependencies = [
"base64 0.21.7",
"serde",
]
[[package]]
name = "pem"
version = "3.0.3"
@ -3940,15 +3881,6 @@ dependencies = [
"serde",
]
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
dependencies = [
"base64ct",
]
[[package]]
name = "percent-encoding"
version = "2.3.1"
@ -4086,27 +4018,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkcs1"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
dependencies = [
"der",
"pkcs8",
"spki",
]
[[package]]
name = "pkcs8"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
dependencies = [
"der",
"spki",
]
[[package]]
name = "pkg-config"
version = "0.3.30"
@ -4619,7 +4530,7 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6"
dependencies = [
"pem 3.0.3",
"pem",
"ring 0.16.20",
"time",
"yasna",
@ -5123,26 +5034,6 @@ dependencies = [
"cc",
]
[[package]]
name = "rsa"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc"
dependencies = [
"const-oid",
"digest",
"num-bigint-dig",
"num-integer",
"num-traits",
"pkcs1",
"pkcs8",
"rand_core 0.6.4",
"signature",
"spki",
"subtle",
"zeroize",
]
[[package]]
name = "rstar"
version = "0.11.0"
@ -5663,16 +5554,6 @@ dependencies = [
"libc",
]
[[package]]
name = "signature"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"digest",
"rand_core 0.6.4",
]
[[package]]
name = "simdutf8"
version = "0.1.4"
@ -5786,16 +5667,6 @@ dependencies = [
"lock_api",
]
[[package]]
name = "spki"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
dependencies = [
"base64ct",
"der",
]
[[package]]
name = "stable-pattern"
version = "0.1.0"
@ -6066,6 +5937,7 @@ dependencies = [
"hex",
"indxdb",
"ipnet",
"jsonwebtoken",
"lexicmp",
"linfa-linalg",
"md-5",
@ -6107,7 +5979,6 @@ dependencies = [
"snap",
"storekey",
"surrealdb-derive",
"surrealdb-jsonwebtoken",
"surrealdb-tikv-client",
"surrealkv",
"surrealml-core",
@ -6141,25 +6012,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "surrealdb-jsonwebtoken"
version = "8.3.0-surreal.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d4f759c65df8a8cf2d83c99db7fdd3ae5b8fff05fa7fe69a8612f29dd5f99b"
dependencies = [
"base64 0.21.7",
"getrandom 0.2.12",
"hmac",
"pem 2.0.1",
"rand 0.8.5",
"ring 0.16.20",
"rsa",
"serde",
"serde_json",
"sha2",
"simple_asn1",
]
[[package]]
name = "surrealdb-tikv-client"
version = "0.3.0-surreal.1"

View file

@ -95,7 +95,7 @@ js = { version = "0.6.2", package = "rquickjs", features = [
"properties",
"rust-alloc",
], optional = true }
jsonwebtoken = { version = "8.3.0-surreal.1", package = "surrealdb-jsonwebtoken" }
jsonwebtoken = "9.3.0"
lexicmp = "0.1.0"
linfa-linalg = "=0.1.0"
md-5 = "0.10.6"

View file

@ -2,7 +2,9 @@ use crate::dbs::capabilities::NetTarget;
use crate::err::Error;
use crate::kvs::Datastore;
use chrono::{DateTime, Duration, Utc};
use jsonwebtoken::jwk::{AlgorithmParameters::*, Jwk, JwkSet, KeyOperations, PublicKeyUse};
use jsonwebtoken::jwk::{
AlgorithmParameters::*, Jwk, JwkSet, KeyAlgorithm, KeyOperations, PublicKeyUse,
};
use jsonwebtoken::{Algorithm::*, DecodingKey, Validation};
use once_cell::sync::Lazy;
use reqwest::{Client, Url};
@ -114,8 +116,25 @@ pub(super) async fn config(
// When missing, tokens must be validated using only the required key type parameter
// This is discouraged, as it requires relying on the algorithm specified in the token
// Source: https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
let alg = match jwk.common.algorithm {
Some(alg) => alg,
let alg = match jwk.common.key_algorithm {
Some(alg) => match alg {
KeyAlgorithm::HS256 => HS256,
KeyAlgorithm::HS384 => HS384,
KeyAlgorithm::HS512 => HS512,
KeyAlgorithm::EdDSA => EdDSA,
KeyAlgorithm::ES256 => ES256,
KeyAlgorithm::ES384 => ES384,
KeyAlgorithm::PS256 => PS256,
KeyAlgorithm::PS384 => PS384,
KeyAlgorithm::PS512 => PS512,
KeyAlgorithm::RS256 => RS256,
KeyAlgorithm::RS384 => RS384,
KeyAlgorithm::RS512 => RS512,
_ => {
warn!("Unspported value for parameter 'alg' in JWK object: '{:?}'", alg);
return Err(Error::InvalidAuth); // Return opaque error
}
},
// If not specified, use the algorithm provided in the token header
// It is critical that the JWT library prevents the "none" algorithm from being used
// Reference: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#Meet-the--None--Algorithm
@ -342,7 +361,7 @@ mod tests {
common: jsonwebtoken::jwk::CommonParameters {
public_key_use: Some(jsonwebtoken::jwk::PublicKeyUse::Signature),
key_operations: None,
algorithm: Some(jsonwebtoken::Algorithm::RS256),
key_algorithm: Some(KeyAlgorithm::RS256),
key_id: Some("test_1".to_string()),
x509_url: None,
x509_chain: Some(vec![
@ -363,7 +382,7 @@ mod tests {
common: jsonwebtoken::jwk::CommonParameters {
public_key_use: Some(jsonwebtoken::jwk::PublicKeyUse::Signature),
key_operations: None,
algorithm: Some(jsonwebtoken::Algorithm::RS256),
key_algorithm: Some(KeyAlgorithm::RS256),
key_id: Some("test_2".to_string()),
x509_url: None,
x509_chain: Some(vec![
@ -629,7 +648,7 @@ mod tests {
)),
);
let mut jwks = DEFAULT_JWKS.clone();
jwks.keys[0].common.algorithm = None;
jwks.keys[0].common.key_algorithm = None;
let jwks_path = format!("{}/jwks.json", random_path());
let mock_server = MockServer::start().await;
@ -667,7 +686,7 @@ mod tests {
)),
);
let mut jwks = DEFAULT_JWKS.clone();
jwks.keys[0].common.algorithm = None;
jwks.keys[0].common.key_algorithm = None;
let jwks_path = format!("{}/jwks.json", random_path());
let mock_server = MockServer::start().await;
@ -693,6 +712,39 @@ mod tests {
);
}
#[tokio::test]
async fn test_unsupported_algorithm() {
let ds = Datastore::new("memory").await.unwrap().with_capabilities(
Capabilities::default().with_network_targets(Targets::<NetTarget>::Some(
[NetTarget::from_str("127.0.0.1").unwrap()].into(),
)),
);
let mut jwks = DEFAULT_JWKS.clone();
jwks.keys[0].common.key_algorithm = Some(KeyAlgorithm::RSA_OAEP_256);
let jwks_path = format!("{}/jwks.json", random_path());
let mock_server = MockServer::start().await;
let response = ResponseTemplate::new(200).set_body_json(jwks);
Mock::given(method("GET"))
.and(path(&jwks_path))
.respond_with(response)
.mount(&mock_server)
.await;
let url = mock_server.uri();
let res = config(
&ds,
"test_1",
&format!("{}/{}", &url, &jwks_path),
jsonwebtoken::Algorithm::RS256,
)
.await;
assert!(
res.is_err(),
"Unexpected success validating token with key specifies an unsupported algorithm"
);
}
#[tokio::test]
async fn test_no_key_use() {
let ds = Datastore::new("memory").await.unwrap().with_capabilities(

View file

@ -16,47 +16,55 @@ use std::str::{self, FromStr};
use std::sync::Arc;
fn config(alg: Algorithm, key: &[u8]) -> Result<(DecodingKey, Validation), Error> {
match alg {
let (dec, mut val) = match alg {
Algorithm::Hs256 => {
Ok((DecodingKey::from_secret(key), Validation::new(jsonwebtoken::Algorithm::HS256)))
(DecodingKey::from_secret(key), Validation::new(jsonwebtoken::Algorithm::HS256))
}
Algorithm::Hs384 => {
Ok((DecodingKey::from_secret(key), Validation::new(jsonwebtoken::Algorithm::HS384)))
(DecodingKey::from_secret(key), Validation::new(jsonwebtoken::Algorithm::HS384))
}
Algorithm::Hs512 => {
Ok((DecodingKey::from_secret(key), Validation::new(jsonwebtoken::Algorithm::HS512)))
(DecodingKey::from_secret(key), Validation::new(jsonwebtoken::Algorithm::HS512))
}
Algorithm::EdDSA => {
Ok((DecodingKey::from_ed_pem(key)?, Validation::new(jsonwebtoken::Algorithm::EdDSA)))
(DecodingKey::from_ed_pem(key)?, Validation::new(jsonwebtoken::Algorithm::EdDSA))
}
Algorithm::Es256 => {
Ok((DecodingKey::from_ec_pem(key)?, Validation::new(jsonwebtoken::Algorithm::ES256)))
(DecodingKey::from_ec_pem(key)?, Validation::new(jsonwebtoken::Algorithm::ES256))
}
Algorithm::Es384 => {
Ok((DecodingKey::from_ec_pem(key)?, Validation::new(jsonwebtoken::Algorithm::ES384)))
(DecodingKey::from_ec_pem(key)?, Validation::new(jsonwebtoken::Algorithm::ES384))
}
Algorithm::Es512 => {
Ok((DecodingKey::from_ec_pem(key)?, Validation::new(jsonwebtoken::Algorithm::ES384)))
(DecodingKey::from_ec_pem(key)?, Validation::new(jsonwebtoken::Algorithm::ES384))
}
Algorithm::Ps256 => {
Ok((DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::PS256)))
(DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::PS256))
}
Algorithm::Ps384 => {
Ok((DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::PS384)))
(DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::PS384))
}
Algorithm::Ps512 => {
Ok((DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::PS512)))
(DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::PS512))
}
Algorithm::Rs256 => {
Ok((DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::RS256)))
(DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::RS256))
}
Algorithm::Rs384 => {
Ok((DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::RS384)))
(DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::RS384))
}
Algorithm::Rs512 => {
Ok((DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::RS512)))
(DecodingKey::from_rsa_pem(key)?, Validation::new(jsonwebtoken::Algorithm::RS512))
}
}
};
// TODO(gguillemas): This keeps the existing behavior as of SurrealDB 2.0.0-alpha.9.
// Up to that point, a fork of the "jsonwebtoken" crate in version 8.3.0 was being used.
// Now that the audience claim is validated by default, we should allow users to leverage this.
// This will most likely involve defining an audience string via "DEFINE ACCESS ... TYPE JWT".
val.validate_aud = false;
Ok((dec, val))
}
static KEY: Lazy<DecodingKey> = Lazy::new(|| DecodingKey::from_secret(&[]));
@ -66,6 +74,7 @@ static DUD: Lazy<Validation> = Lazy::new(|| {
validation.insecure_disable_signature_validation();
validation.validate_nbf = false;
validation.validate_exp = false;
validation.validate_aud = false;
validation
});
@ -1728,7 +1737,7 @@ mod tests {
common: jsonwebtoken::jwk::CommonParameters {
public_key_use: None,
key_operations: None,
algorithm: Some(jsonwebtoken::Algorithm::HS512),
key_algorithm: Some(jsonwebtoken::jwk::KeyAlgorithm::HS512),
key_id: Some(kid.to_string()),
x509_url: None,
x509_chain: None,

View file

@ -61,12 +61,7 @@ notice = "warn"
# Threshold for security vulnerabilities: None, Low, Medium, High, Critical.
severity-threshold = "None"
# A list of security advisory identifiers to ignore.
ignore = [
# Will be resolved once "surrealdb-jsonwebtoken", a temporary fork
# of "jsonwebtoken", is replaced by the upstream version which no
# longer uses the affected "rsa" crate.
"RUSTSEC-2023-0071",
]
ignore = []
# --------------------------------------------------
# LICENSES

678
lib/fuzz/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -166,12 +166,6 @@ user-id = 145457 # Tobie Morgan Hitchcock (tobiemh)
start = "2022-02-26"
end = "2025-01-24"
[[trusted.surrealdb-jsonwebtoken]]
criteria = "safe-to-deploy"
user-id = 3987 # Rushmore Mushambi (rushmorem)
start = "2023-08-29"
end = "2025-01-24"
[[trusted.surrealdb-tikv-client]]
criteria = "safe-to-deploy"
user-id = 217605 # Yusuke Kuoka (mumoshu)

View file

@ -411,10 +411,6 @@ criteria = "safe-to-deploy"
version = "0.1.7"
criteria = "safe-to-deploy"
[[exemptions.const-oid]]
version = "0.9.6"
criteria = "safe-to-deploy"
[[exemptions.convert_case]]
version = "0.6.0"
criteria = "safe-to-deploy"
@ -503,10 +499,6 @@ criteria = "safe-to-run"
version = "0.1.3"
criteria = "safe-to-run"
[[exemptions.der]]
version = "0.7.9"
criteria = "safe-to-deploy"
[[exemptions.deunicode]]
version = "1.4.3"
criteria = "safe-to-deploy"
@ -833,7 +825,7 @@ criteria = "safe-to-deploy"
[[exemptions.jsonwebtoken]]
version = "9.3.0"
criteria = "safe-to-run"
criteria = "safe-to-deploy"
[[exemptions.lalrpop]]
version = "0.20.2"
@ -1007,10 +999,6 @@ criteria = "safe-to-deploy"
version = "0.2.0"
criteria = "safe-to-deploy"
[[exemptions.num-bigint-dig]]
version = "0.8.4"
criteria = "safe-to-deploy"
[[exemptions.num-complex]]
version = "0.4.5"
criteria = "safe-to-deploy"
@ -1099,16 +1087,8 @@ criteria = "safe-to-deploy"
version = "0.2.9"
criteria = "safe-to-deploy"
[[exemptions.pem]]
version = "2.0.1"
criteria = "safe-to-deploy"
[[exemptions.pem]]
version = "3.0.3"
criteria = "safe-to-run"
[[exemptions.pem-rfc7468]]
version = "0.7.0"
criteria = "safe-to-deploy"
[[exemptions.petgraph]]
@ -1151,14 +1131,6 @@ criteria = "safe-to-deploy"
version = "1.1.5"
criteria = "safe-to-deploy"
[[exemptions.pkcs1]]
version = "0.7.5"
criteria = "safe-to-deploy"
[[exemptions.pkcs8]]
version = "0.10.2"
criteria = "safe-to-deploy"
[[exemptions.plotters]]
version = "0.3.5"
criteria = "safe-to-deploy"
@ -1357,7 +1329,7 @@ criteria = "safe-to-deploy"
[[exemptions.ring]]
version = "0.16.20"
criteria = "safe-to-deploy"
criteria = "safe-to-run"
[[exemptions.ring]]
version = "0.17.8"
@ -1423,10 +1395,6 @@ criteria = "safe-to-deploy"
version = "0.6.2"
criteria = "safe-to-deploy"
[[exemptions.rsa]]
version = "0.9.6"
criteria = "safe-to-deploy"
[[exemptions.rstar]]
version = "0.11.0"
criteria = "safe-to-deploy"
@ -1629,16 +1597,12 @@ criteria = "safe-to-deploy"
[[exemptions.spin]]
version = "0.5.2"
criteria = "safe-to-deploy"
criteria = "safe-to-run"
[[exemptions.spin]]
version = "0.9.8"
criteria = "safe-to-deploy"
[[exemptions.spki]]
version = "0.7.3"
criteria = "safe-to-deploy"
[[exemptions.stable-pattern]]
version = "0.1.0"
criteria = "safe-to-deploy"

View file

@ -268,13 +268,6 @@ user-id = 145457
user-login = "tobiemh"
user-name = "Tobie Morgan Hitchcock"
[[publisher.surrealdb-jsonwebtoken]]
version = "8.3.0-surreal.1"
when = "2023-08-29"
user-id = 3987
user-login = "rushmorem"
user-name = "Rushmore Mushambi"
[[publisher.surrealdb-tikv-client]]
version = "0.3.0-surreal.1"
when = "2024-06-24"
@ -1183,11 +1176,6 @@ who = "David Cook <dcook@divviup.org>"
criteria = "safe-to-deploy"
delta = "0.1.45 -> 0.1.46"
[[audits.isrg.audits.num-iter]]
who = "David Cook <dcook@divviup.org>"
criteria = "safe-to-deploy"
delta = "0.1.43 -> 0.1.44"
[[audits.isrg.audits.num-traits]]
who = "David Cook <dcook@divviup.org>"
criteria = "safe-to-deploy"
@ -1598,13 +1586,6 @@ version = "0.1.45"
notes = "All code written or reviewed by Josh Stone."
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.num-iter]]
who = "Josh Stone <jistone@redhat.com>"
criteria = "safe-to-deploy"
version = "0.1.43"
notes = "All code written or reviewed by Josh Stone."
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.num-traits]]
who = "Josh Stone <jistone@redhat.com>"
criteria = "safe-to-deploy"
@ -2116,22 +2097,6 @@ delta = "0.1.4 -> 0.1.7"
notes = "Only change to an `unsafe` block is to fix a clippy lint."
aggregated-from = "https://raw.githubusercontent.com/zcash/zcash/master/qa/supply-chain/audits.toml"
[[audits.zcash.audits.signature]]
who = "Daira Emma Hopwood <daira@jacaranda.org>"
criteria = "safe-to-deploy"
version = "2.1.0"
notes = """
This crate uses `#![forbid(unsafe_code)]`, has no build script, and only provides traits with some trivial default implementations.
I did not review whether implementing these APIs would present any undocumented cryptographic hazards.
"""
aggregated-from = "https://raw.githubusercontent.com/zcash/zcash/master/qa/supply-chain/audits.toml"
[[audits.zcash.audits.signature]]
who = "Jack Grigg <jack@electriccoin.co>"
criteria = "safe-to-deploy"
delta = "2.1.0 -> 2.2.0"
aggregated-from = "https://raw.githubusercontent.com/zcash/zcash/master/qa/supply-chain/audits.toml"
[[audits.zcash.audits.thiserror]]
who = "Jack Grigg <jack@electriccoin.co>"
criteria = "safe-to-deploy"