github.com/yogeshkumararora/slsa-github-generator@v1.10.1-0.20240520161934-11278bd5afb4/signing/envelope/envelope.go (about) 1 // Copyright 2023 SLSA Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package envelope 16 17 import ( 18 "encoding/json" 19 "fmt" 20 21 "github.com/secure-systems-lab/go-securesystemslib/dsse" 22 "github.com/sigstore/sigstore/pkg/cryptoutils" 23 ) 24 25 /* 26 Envelope captures an envelope as described by the Secure Systems Lab 27 Signing Specification. See here: 28 https://github.com/secure-systems-lab/signing-spec/blob/master/envelope.md 29 */ 30 type Envelope struct { 31 PayloadType string `json:"payloadType"` 32 Payload string `json:"payload"` 33 Signatures []Signature `json:"signatures"` 34 } 35 36 /* 37 Signature represents a generic in-toto signature that contains the identifier 38 of the key which was used to create the signature. 39 The used signature scheme has to be agreed upon by the signer and verifer 40 out of band. 41 The signature is a base64 encoding of the raw bytes from the signature 42 algorithm. 43 The cert is a PEM encoded string of the signing certificate. 44 */ 45 type Signature struct { 46 KeyID string `json:"keyid"` 47 Sig string `json:"sig"` 48 Cert string `json:"cert"` 49 } 50 51 // AddCertToEnvelope takes a signed DSSE Envelope and a PEM-encoded certificate, and 52 // returns an Envelope with the certificate inside the Signature of the Envelope. 53 // This assumes there is only one signature present in the envelope. 54 func AddCertToEnvelope(signedAtt, cert []byte) ([]byte, error) { 55 // Unmarshal into a DSSE envelope. 56 env := &dsse.Envelope{} 57 if err := json.Unmarshal(signedAtt, env); err != nil { 58 return nil, err 59 } 60 61 // Create an envelope.Envelope. 62 envWithCert := &Envelope{ 63 PayloadType: env.PayloadType, 64 Payload: env.Payload, 65 Signatures: []Signature{}, 66 } 67 68 if len(env.Signatures) != 1 { 69 return nil, fmt.Errorf("expected exactly one signature in the envelope") 70 } 71 72 if certs, err := cryptoutils.UnmarshalCertificatesFromPEM(cert); err != nil || len(certs) != 1 { 73 return nil, fmt.Errorf("invalid certificate, expected PEM encoded certificate") 74 } 75 76 for _, sig := range env.Signatures { 77 envWithCert.Signatures = append(envWithCert.Signatures, 78 Signature{Sig: sig.Sig, KeyID: sig.KeyID, Cert: string(cert)}) 79 } 80 81 // Return marshalled result 82 return json.Marshal(envWithCert) 83 } 84 85 // GetCertFromEnvelope takes a signed Envelope and extracts the PEM-encoded 86 // certificate from the signature. 87 // This assumes there is only one signature present in the envelope. 88 func GetCertFromEnvelope(signedAtt []byte) ([]byte, error) { 89 // Unmarshal into an envelope. 90 env := &Envelope{} 91 if err := json.Unmarshal(signedAtt, env); err != nil { 92 return nil, err 93 } 94 95 if len(env.Signatures) != 1 { 96 return nil, fmt.Errorf("expected exactly one signature in the envelope") 97 } 98 99 return []byte(env.Signatures[0].Cert), nil 100 }