From 48fb0e9985b8a0d79d2635e409f659a38d1f40eb Mon Sep 17 00:00:00 2001 From: Sree Revoori Date: Mon, 29 Jan 2024 16:39:04 +0000 Subject: [PATCH] Use different go CMS/CSR parsing library The previous pkcs7 library does not allow SubjectKeyIdentifier SignerIdentifiers, which some platforms may allow. We now use a different parsing library that supports both types of SignerIdentifiers. --- dpe/src/commands/certify_key.rs | 8 ++++---- platform/src/default.rs | 11 ++++++++--- platform/src/lib.rs | 12 +++++++++--- verification/testing/certifyKey.go | 21 ++++++++++++++++----- verification/testing/go.mod | 2 +- verification/testing/go.sum | 24 ++++++++++++++++++++++-- 6 files changed, 60 insertions(+), 18 deletions(-) diff --git a/dpe/src/commands/certify_key.rs b/dpe/src/commands/certify_key.rs index 577ecb6e..cde41f84 100644 --- a/dpe/src/commands/certify_key.rs +++ b/dpe/src/commands/certify_key.rs @@ -10,7 +10,7 @@ use crate::{ }; use bitflags::bitflags; use crypto::Crypto; -use platform::{Platform, MAX_CHUNK_SIZE}; +use platform::{Platform, MAX_ISSUER_NAME_SIZE}; #[repr(C)] #[derive(Debug, PartialEq, Eq, zerocopy::FromBytes, zerocopy::AsBytes)] @@ -103,7 +103,7 @@ impl CommandExecution for CertifyKeyCmd { supports_recursive: dpe.support.recursive(), }; - let mut issuer_name = [0u8; MAX_CHUNK_SIZE]; + let mut issuer_name = [0u8; MAX_ISSUER_NAME_SIZE]; let issuer_len = env.platform.get_issuer_name(&mut issuer_name)?; let mut cert = [0u8; MAX_CERT_SIZE]; @@ -111,7 +111,7 @@ impl CommandExecution for CertifyKeyCmd { Self::FORMAT_X509 => { let mut tbs_buffer = [0u8; MAX_CERT_SIZE]; let mut tbs_writer = CertWriter::new(&mut tbs_buffer, true); - if issuer_len > MAX_CHUNK_SIZE { + if issuer_len > MAX_ISSUER_NAME_SIZE { return Err(DpeErrorCode::InternalError); } let cert_validity = env.platform.get_cert_validity()?; @@ -147,7 +147,7 @@ impl CommandExecution for CertifyKeyCmd { let mut cert_req_info_buffer = [0u8; MAX_CERT_SIZE]; let mut cert_req_info_writer = CertWriter::new(&mut cert_req_info_buffer, true); - if issuer_len > MAX_CHUNK_SIZE { + if issuer_len > MAX_ISSUER_NAME_SIZE { return Err(DpeErrorCode::InternalError); } let mut bytes_written = cert_req_info_writer.encode_certification_request_info( diff --git a/platform/src/default.rs b/platform/src/default.rs index 42e3ca7d..a92bbcbd 100644 --- a/platform/src/default.rs +++ b/platform/src/default.rs @@ -1,6 +1,8 @@ // Licensed under the Apache-2.0 license -use crate::{CertValidity, Platform, PlatformError, SignerIdentifier, MAX_CHUNK_SIZE}; +use crate::{ + CertValidity, Platform, PlatformError, SignerIdentifier, MAX_CHUNK_SIZE, MAX_ISSUER_NAME_SIZE, +}; use arrayvec::ArrayVec; use cfg_if::cfg_if; use core::cmp::min; @@ -103,7 +105,10 @@ impl Platform for DefaultPlatform { Ok(bytes_written) } - fn get_issuer_name(&mut self, out: &mut [u8; MAX_CHUNK_SIZE]) -> Result { + fn get_issuer_name( + &mut self, + out: &mut [u8; MAX_ISSUER_NAME_SIZE], + ) -> Result { let issuer_name = parse::DefaultPlatform::parse_issuer_name(); if issuer_name.len() > out.len() { return Err(PlatformError::IssuerNameError(0)); @@ -113,7 +118,7 @@ impl Platform for DefaultPlatform { } fn get_signer_identifier(&mut self) -> Result { - let mut issuer_name = [0u8; MAX_CHUNK_SIZE]; + let mut issuer_name = [0u8; MAX_ISSUER_NAME_SIZE]; let issuer_len = self.get_issuer_name(&mut issuer_name)?; let sn = parse::DefaultPlatform::parse_issuer_sn(); let mut issuer_name_vec = ArrayVec::new(); diff --git a/platform/src/lib.rs b/platform/src/lib.rs index da4524fa..0a1bcf58 100644 --- a/platform/src/lib.rs +++ b/platform/src/lib.rs @@ -16,14 +16,17 @@ pub mod default; pub mod printer; pub const MAX_CHUNK_SIZE: usize = 2048; +pub const MAX_ISSUER_NAME_SIZE: usize = 128; pub const MAX_SN_SIZE: usize = 20; +pub const MAX_SKI_SIZE: usize = 20; +#[allow(variant_size_differences)] pub enum SignerIdentifier { IssuerAndSerialNumber { - issuer_name: ArrayVec, + issuer_name: ArrayVec, serial_number: ArrayVec, }, - SubjectKeyIdentifier(ArrayVec), + SubjectKeyIdentifier(ArrayVec), } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -83,7 +86,10 @@ pub trait Platform { /// # Arguments /// /// * `out` - Output buffer for issuer name to be written to. - fn get_issuer_name(&mut self, out: &mut [u8; MAX_CHUNK_SIZE]) -> Result; + fn get_issuer_name( + &mut self, + out: &mut [u8; MAX_ISSUER_NAME_SIZE], + ) -> Result; /// Retrieves a CMS Content Info's signer identifier /// diff --git a/verification/testing/certifyKey.go b/verification/testing/certifyKey.go index 39160cb3..ff8fdeac 100644 --- a/verification/testing/certifyKey.go +++ b/verification/testing/certifyKey.go @@ -17,7 +17,7 @@ import ( "testing" "time" - "go.mozilla.org/pkcs7" + cms "github.com/github/smimesign/ietf-cms" "github.com/chipsalliance/caliptra-dpe/verification/client" zx509 "github.com/zmap/zcrypto/x509" @@ -150,7 +150,7 @@ func TestCertifyKeyCsr(d client.TestDPEInstance, c client.DPEClient, t *testing. t.Fatalf("[FATAL]: Could not certify key: %v", err) } - wrappedCSR, err := pkcs7.Parse(certifyKeyResp.Certificate) + wrappedCSR, err := cms.ParseSignedData(certifyKeyResp.Certificate) if err != nil { t.Fatalf("[FATAL]: Could not unmarshal CSR CMS message: %v", err) } @@ -171,13 +171,24 @@ func TestCertifyKeyCsr(d client.TestDPEInstance, c client.DPEClient, t *testing. // those verifying the signatures have an alternate means of // obtaining necessary certificates (e.g., from a previous set // of certificates). - wrappedCSR.Certificates = append(wrappedCSR.Certificates, certChain...) - err = wrappedCSR.Verify() + err = wrappedCSR.SetCertificates(certChain) + if err != nil { + t.Errorf("[ERROR]: Failed to add certificates to SignedData: %v", err) + } + certPool := x509.NewCertPool() + for _, cert := range certChain { + certPool.AddCert(cert) + } + _, err = wrappedCSR.Verify(x509.VerifyOptions{Roots: certPool}) if err != nil { t.Errorf("[ERROR]: Failed to verify CMS wrapper signature: %v", err) } - csr, err := x509.ParseCertificateRequest(wrappedCSR.Content) + content, err := wrappedCSR.GetData() + if err != nil { + t.Fatalf("[FATAL]: Could not get CMS content: %v", err) + } + csr, err := x509.ParseCertificateRequest(content) if err != nil { t.Fatalf("[FATAL]: Could not parse CSR: %v", err) } diff --git a/verification/testing/go.mod b/verification/testing/go.mod index 442549a7..c7e1f1c3 100644 --- a/verification/testing/go.mod +++ b/verification/testing/go.mod @@ -6,11 +6,11 @@ replace github.com/chipsalliance/caliptra-dpe/verification/client => ../client require ( github.com/chipsalliance/caliptra-dpe/verification/client v0.0.0-00010101000000-000000000000 + github.com/github/smimesign v0.2.0 github.com/google/go-tpm v0.9.0 github.com/google/go-tpm-tools v0.4.1 github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 github.com/zmap/zlint/v3 v3.4.1 - go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 ) diff --git a/verification/testing/go.sum b/verification/testing/go.sum index 97dc3e12..7e59fb99 100644 --- a/verification/testing/go.sum +++ b/verification/testing/go.sum @@ -1,13 +1,21 @@ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/github/smimesign v0.2.0 h1:Hho4YcX5N1I9XNqhq0fNx0Sts8MhLonHd+HRXVGNjvk= +github.com/github/smimesign v0.2.0/go.mod h1:iZiiwNT4HbtGRVqCQu7uJPEZCuEE5sfSSttcnePkDl4= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/google/certificate-transparency-go v1.1.2 h1:4hE0GEId6NAW28dFpC+LrRGwQX5dtmXQGDbg8+/MZOM= +github.com/google/go-attestation v0.5.0 h1:jXtAWT2sw2Yu8mYU0BC7FDidR+ngxFPSE+pl6IUu3/0= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -19,24 +27,30 @@ github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/go-tpm-tools v0.4.1 h1:gYU6iwRo0tY3V6NDnS6m+XYog+b3g6YFhHQl3sYaUL4= github.com/google/go-tpm-tools v0.4.1/go.mod h1:w03m0jynhTo7puXTYoyfpNOMqyQ9SB7sixnKWsS/1L0= +github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/pborman/getopt v0.0.0-20180811024354-2b5b3bfb099b/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -44,8 +58,10 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db h1:/WcxBne+5CbtbgWd/sV2wbravmr4sT7y52ifQaCgoLs= github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db/go.mod h1:aiQaH1XpzIfgrJq3S1iw7w+3EDbRP7mF5fmwUhWyRUs= @@ -61,10 +77,10 @@ github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21 github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= github.com/zmap/zlint/v3 v3.4.1 h1:zhGB2Q1oPNS+bODC5tTPlKDOnLfDGyxejgAEp1SfFiQ= github.com/zmap/zlint/v3 v3.4.1/go.mod h1:WgepL2QqxyMHnrOWJ54NqrgfMtOyuXr52wEE0tcfo9k= -go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak= -go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -130,6 +146,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= @@ -138,6 +156,8 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=