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  }