Documentation ¶
Index ¶
- Constants
- Variables
- func CreateCertificateFromPEM(data string) (*x509.Certificate, error)
- func CurrentTimestamp() int64
- func EpochToDateString(epoch int64) string
- func ValidateAndRemovePrefix(in string) (string, error)
- func ZlibDecompress(input []byte) ([]byte, error)
- type CWTClaims
- type CovidCertificate
- type DGC
- func (d *DGC) CreateSigStructure() ([]byte, error)
- func (d *DGC) GetAlgorithm() (*cose.Algorithm, error)
- func (d *DGC) GetCertificate(countryCode string, keyIdentifier []byte) (*x509.Certificate, error)
- func (d *DGC) GetDigest(toBeSigned []byte, algorithm *cose.Algorithm) ([]byte, error)
- func (d *DGC) GetKeyIdentifier() ([]byte, error)
- func (d *DGC) ToJSONClaims() (string, error)
- func (d *DGC) ToJSONHealthCertificate() (string, error)
- func (d *DGC) Verify() (bool, error)
- func (d *DGC) VerifyWithCertificate(certificate *x509.Certificate) (bool, error)
- type HealthCertificate
- type Name
- type RecoveryRecord
- type SignedCWT
- type SigningHeader
- type TestRecord
- type TrustURLCertificate
- type TrustURLResponse
- type TrustedCertificatesStruct
- type VaccineRecord
Constants ¶
const ( // TrustURL is the provider of trusted certificates TrustURL = "https://raw.githubusercontent.com/section42/hcert-trustlist-mirror/main/trustlist_de.min.json" // ContextSignature is the context field of SigStructure while creating the digest of the COSE ContextSignature = "Signature1" // ExpirationTrustedCertificates is the expiration constant (12 Hours) to indicate that trusted certificates should be fetched again ExpirationTrustedCertificates = 3600 * 12 )
const ( HealthCertificatePrefix = "HC1:" ZlibMagicNumber = 0x78 )
Variables ¶
var AvailableAlgorithms = map[int]*cose.Algorithm{ -7: cose.ES256, -35: cose.ES384, -36: cose.ES512, }
AvailableAlgorithms The algorithms defined in this document can be found in Table 1.
+=======+=======+=========+==================+ | Name | Value | Hash | Description | +=======+=======+=========+==================+ | ES256 | -7 | SHA-256 | ECDSA w/ SHA-256 | +-------+-------+---------+------------------+ | ES384 | -35 | SHA-384 | ECDSA w/ SHA-384 | +-------+-------+---------+------------------+ | ES512 | -36 | SHA-512 | ECDSA w/ SHA-512 | +-------+-------+---------+------------------+ Table 1: ECDSA Algorithm Values
var TrustedCertificates = TrustedCertificatesStruct{ Certificates: []TrustURLCertificate{}, Timestamp: 0, }
TrustedCertificates to keep the public certificates in the memory
Functions ¶
func CreateCertificateFromPEM ¶
func CreateCertificateFromPEM(data string) (*x509.Certificate, error)
CreateCertificateFromPEM simply creates x509.Certificate from the PEM string TESTCTX -> CERTIFICATE field of a given test file
func CurrentTimestamp ¶ added in v0.1.1
func CurrentTimestamp() int64
CurrentTimestamp simply returns the unix time (Number of seconds elapsed since 1 Jan 1970)
func EpochToDateString ¶ added in v0.1.1
EpochToDateString simply returns the RFC3339 format of date
func ValidateAndRemovePrefix ¶
ValidateAndRemovePrefix simply checks if QR code has a prefix "HC1:" and returns trimmed qr code (without prefix)
func ZlibDecompress ¶
ZlibDecompress simply decompressed the input and returns the decompressed []byte
Types ¶
type CWTClaims ¶
type CWTClaims struct { Issuer string `cbor:"1,keyasint" json:"iss"` ExpirationTime int64 `cbor:"4,keyasint" json:"exp"` IssuedAt int64 `cbor:"6,keyasint" json:"iat"` HealthCertificate HealthCertificate `cbor:"-260,keyasint" json:"hcert"` }
CWTClaims
3.3 CWT CWTClaims 3.3.1 CWT Structure Overview • Protected Header • Signature Algorithm (alg, label 1) • Key Identifier (kid, label 4) • Payload • Issuer (iss, claim key 1, optional, ISO 3166-1 alpha-2 of issuer) • IssuedAt (iat, claim key 6) • ExpirationTime (exp, claim key 4) • HealthCertificate (hcert, claim key -260) – EU Digital Green Certificate v1 (eu_dgc_v1, claim key 1) • Signature
type CovidCertificate ¶
type CovidCertificate struct { Version string `cbor:"ver" json:"ver"` PersonalName Name `cbor:"nam" json:"nam"` DateOfBirth string `cbor:"dob" json:"dob"` VaccineRecords []VaccineRecord `cbor:"v" json:"v,omitempty"` TestRecords []TestRecord `cbor:"t" json:"t,omitempty"` RecoveryRecords []RecoveryRecord `cbor:"r" json:"r,omitempty"` }
CovidCertificate https://ec.europa.eu/health/sites/default/files/ehealth/docs/covid-certificate_json_specification_en.pdf
type DGC ¶
type DGC struct { V SignedCWT P SigningHeader Claims CWTClaims Cert *x509.Certificate }
DGC The general structure to keep SignedCWT, SigningHeader, CWTClaims, Cert (will be assigned after verification)
func DecodeCOSE ¶
DecodeCOSE simply decodes the coseData and returns DGC without CERT field. The Cert field will be populated once the DGC is verified
func Verify ¶
Verify applies the following algorithm to create verified DGC
- Prefix validation
- Base45 decoding
- ZLIB decompression
- Decoding the CBOR data
- Verification with KID against the trusted list database - Extracting the KID and Issuer (country code) - Searching the KID and country code in the trusted list database - Creating digest of the certificate using the algorithm of the certificate - Verifying the certificate using its digest and signature
func VerifyAPI ¶ added in v0.1.3
VerifyAPI applies the following algorithm to create verified DGC. Returns the DGC always if the 4th phase is passed with verification flag and error if exists
- Prefix validation
- Base45 decoding
- ZLIB decompression
- Decoding the CBOR data
- Verification with KID against the trusted list database - Extracting the KID and Issuer (country code) - Searching the KID and country code in the trusted list database - Creating digest of the certificate using the algorithm of the certificate - Verifying the certificate using its digest and signature
func VerifyWithCertificate ¶
func VerifyWithCertificate(qrCode string, certificate *x509.Certificate) (*DGC, error)
VerifyWithCertificate applies the following algorithm to create verified DGC
- Prefix validation
- Base45 decoding
- ZLIB decompression
- Decoding the CBOR data
- Verification with provided certificate parameter - Creating digest of the certificate using the algorithm of the certificate - Verifying the certificate using its digest and signature
func (*DGC) CreateSigStructure ¶
CreateSigStructure creates the sig structure to be signed by the algorithm hasher 4.4. Signing and Verification Process
In order to create a signature, a well-defined byte stream is needed. The Sig_structure is used to create the canonical form. This signing and verification process takes in the body information (COSE_Sign or COSE_Sign1), the signer information (COSE_Signature), and the application data (external source). A Sig_structure is a CBOR array. The fields of the Sig_structure in order are: 1. A text string identifying the context of the signature. The context string is: "Signature" for signatures using the COSE_Signature structure. "Signature1" for signatures using the COSE_Sign1 structure. "CounterSignature" for signatures used as counter signature attributes. 2. The protected attributes from the body structure encoded in a bstr type. If there are no protected attributes, a bstr of length zero is used. 3. The protected attributes from the signer structure encoded in a bstr type. If there are no protected attributes, a bstr of length zero is used. This field is omitted for the COSE_Sign1 signature structure. 4. The protected attributes from the application encoded in a bstr type. If this field is not supplied, it defaults to a zero- length binary string. (See Section 4.3 for application guidance on constructing this field.) 5. The payload to be signed encoded in a bstr type. The payload is placed here independent of how it is transported. The CDDL fragment that describes the above text is: Sig_structure = [ context : "Signature" / "Signature1" / "CounterSignature", body_protected : empty_or_serialized_map, ? sign_protected : empty_or_serialized_map, external_aad : bstr, payload : bstr ]
func (*DGC) GetAlgorithm ¶
GetAlgorithm retrieves the algorithm from the protected structure if not found tries to retrieve it from the unprotected structure and checks the algorithm in the AvailableAlgorithms to return *cose.Algorithm
func (*DGC) GetCertificate ¶
GetCertificate tries to find the *x509.Certificate of certificate from the trusted list using the country code (Issuer) and the KID (key identifier)
func (*DGC) GetKeyIdentifier ¶
GetKeyIdentifier retrieves the key identifier from the protected structure if not found tries to retrieve it from the unprotected structure
func (*DGC) ToJSONClaims ¶
ToJSONClaims simply returns well indented json string of DGC.Claims
func (*DGC) ToJSONHealthCertificate ¶
ToJSONHealthCertificate simply returns well indented json string of the DGC.Claims.HealthCertificate.DigitalGreenCertificate
func (*DGC) Verify ¶
Verify verifies the certificate against its kid and country code (Issuer) from the trusted urls. if there is a match the public key is returned and the certificate is verified with its digest and signature
func (*DGC) VerifyWithCertificate ¶
func (d *DGC) VerifyWithCertificate(certificate *x509.Certificate) (bool, error)
VerifyWithCertificate test files' key identifiers mostly does not exist in the trusted lists. They are provided with their own certificates. This function verifies a test certificate with provided certificate
type HealthCertificate ¶
type HealthCertificate struct {
DigitalGreenCertificate CovidCertificate `cbor:"1,keyasint" json:"eu_dgc_v1"`
}
HealthCertificate simply keeps the DGC which is CovidCertificate
type Name ¶
type Name struct { FamilyName string `cbor:"fn" json:"fn"` FamilyNameStd string `cbor:"fnt" json:"fnt"` GivenName string `cbor:"gn" json:"gn"` GivenNameStd string `cbor:"gnt" json:"gnt"` }
Name https://ec.europa.eu/health/sites/default/files/ehealth/docs/covid-certificate_json_specification_en.pdf Section: Person name and date of birth: Person name is the official full name of the person, matching the name stated on travel documents. The identifier of the structure is nam. Exactly 1 (one) person name MUST be provided.
type RecoveryRecord ¶
type RecoveryRecord struct { Target string `cbor:"tg" json:"tg"` Country string `cbor:"co" json:"co"` Issuer string `cbor:"is" json:"is"` FirstPositiveTest string `cbor:"fr" json:"fr"` ValidFrom string `cbor:"df" json:"df"` ValidUntil string `cbor:"du" json:"du"` CertificateID string `cbor:"ci" json:"ci"` }
RecoveryRecord https://ec.europa.eu/health/sites/default/files/ehealth/docs/covid-certificate_json_specification_en.pdf Section: Recovery certificate: Recovery group, if present, MUST contain exactly 1 (one) entry describing exactly one recovery statement. All elements of the recovery group are mandatory, empty values are not supported.
type SignedCWT ¶
type SignedCWT struct { Protected []byte Unprotected map[interface{}]interface{} Payload []byte Signature []byte // contains filtered or unexported fields }
SignedCWT https://ec.europa.eu/health/sites/default/files/ehealth/docs/digital-green-certificates_v3_en.pdf 2.6.1 COSE Structure
A COSE structure contains a protected, unprotected and payload object within one CBOR array defined in the Basic Structure of the RFC81527 Name CBOR Major Type Type Protected 2 bstr Payload 2 bstr Signature 2 bstr Unprotected 2 empty
type SigningHeader ¶
type SigningHeader struct { Algorithm int `cbor:"1,keyasint,omitempty"` KeyIdentifiers []byte `cbor:"4,keyasint,omitempty"` }
SigningHeader 2.6.2 Signing Header
The header of COSE contains the used algorithm and the key identifier: Name CBOR Major Type Placement In Header Type Value Description alg 1 protected nint -7/-37 (ES256) Algorithm Field kid 4 protected array First 8 bytes of the hash value KeyIdentifiers Field
type TestRecord ¶
type TestRecord struct { Target string `cbor:"tg" json:"tg"` TestType string `cbor:"tt" json:"tt"` Name string `cbor:"nm" json:"nm"` Manufacturer string `cbor:"ma" json:"ma"` SampleDatetime string `cbor:"sc" json:"sc"` TestResult string `cbor:"tr" json:"tr"` TestingCentre string `cbor:"tc" json:"tc"` Country string `cbor:"co" json:"co"` Issuer string `cbor:"is" json:"is"` CertificateID string `cbor:"ci" json:"ci"` }
TestRecord https://ec.europa.eu/health/sites/default/files/ehealth/docs/covid-certificate_json_specification_en.pdf Section: Test certificate: Test group, if present, MUST contain exactly 1 (one) entry describing exactly one test result.
type TrustURLCertificate ¶
type TrustURLCertificate struct { CertificateType string `json:"certificateType"` Country string `json:"country"` KeyIdentifier string `json:"kid"` RawData string `json:"rawData"` Signature string `json:"signature"` ThumbPrint string `json:"thumbprint"` Timestamp string `json:"timestamp"` }
TrustURLCertificate is a single trust certificate having country, kid and certificate data fields
func (*TrustURLCertificate) GetCertificate ¶
func (c *TrustURLCertificate) GetCertificate() (*x509.Certificate, error)
GetCertificate returns the x509.Certificate of the current trusted certificate using the RawData field
type TrustURLResponse ¶
type TrustURLResponse struct {
Certificates []TrustURLCertificate `json:"certificates"`
}
TrustURLResponse is the initial JSON struct returned from the trusted list GET request
type TrustedCertificatesStruct ¶ added in v0.1.3
type TrustedCertificatesStruct struct { Certificates []TrustURLCertificate Timestamp int64 }
TrustedCertificatesStruct is a struct to keep the trusted certificates response of the TrustURL in the memory to speed up the generation public certificate with an expiration stamp since the data is not changing frequently
func (TrustedCertificatesStruct) HasExpired ¶ added in v0.1.3
func (t TrustedCertificatesStruct) HasExpired() bool
HasExpired returns true either there are no certificates or timestamp has already expired
type VaccineRecord ¶
type VaccineRecord struct { Target string `cbor:"tg" json:"tg"` Vaccine string `cbor:"vp" json:"vp"` Product string `cbor:"mp" json:"mp"` Manufacturer string `cbor:"ma" json:"ma"` Doses float64 `cbor:"dn" json:"dn"` DoseSeries float64 `cbor:"sd" json:"sd"` Date string `cbor:"dt" json:"dt"` Country string `cbor:"co" json:"co"` Issuer string `cbor:"is" json:"is"` CertificateID string `cbor:"ci" json:"ci"` }
VaccineRecord https://ec.europa.eu/health/sites/default/files/ehealth/docs/covid-certificate_json_specification_en.pdf Section: Certificate type specific information - Vaccination certificate: Vaccination group, if present, MUST contain exactly 1 (one) entry describing exactly one vaccination event. All elements of the vaccination group are mandatory, empty values are not supported.