...

Source file src/github.com/sigstore/rekor/pkg/pki/ssh/encode.go

Documentation: github.com/sigstore/rekor/pkg/pki/ssh

     1  //
     2  // Copyright 2021 The Sigstore Authors.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package ssh
    17  
    18  import (
    19  	"encoding/pem"
    20  	"errors"
    21  	"fmt"
    22  
    23  	"golang.org/x/crypto/ssh"
    24  )
    25  
    26  const (
    27  	namespace = "file"
    28  	pemType   = "SSH SIGNATURE"
    29  )
    30  
    31  func Armor(s *ssh.Signature, p ssh.PublicKey) []byte {
    32  	sig := WrappedSig{
    33  		Version:       1,
    34  		PublicKey:     string(p.Marshal()),
    35  		Namespace:     namespace,
    36  		HashAlgorithm: defaultHashAlgorithm,
    37  		Signature:     string(ssh.Marshal(s)),
    38  	}
    39  
    40  	copy(sig.MagicHeader[:], magicHeader)
    41  
    42  	enc := pem.EncodeToMemory(&pem.Block{
    43  		Type:  pemType,
    44  		Bytes: ssh.Marshal(sig),
    45  	})
    46  	return enc
    47  }
    48  
    49  func Decode(b []byte) (*Signature, error) {
    50  	pemBlock, _ := pem.Decode(b)
    51  	if pemBlock == nil {
    52  		return nil, errors.New("unable to decode pem file")
    53  	}
    54  
    55  	if pemBlock.Type != pemType {
    56  		return nil, fmt.Errorf("wrong pem block type: %s. Expected SSH-SIGNATURE", pemBlock.Type)
    57  	}
    58  
    59  	// Now we unmarshal it into the Signature block
    60  	sig := WrappedSig{}
    61  	if err := ssh.Unmarshal(pemBlock.Bytes, &sig); err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	if sig.Version != 1 {
    66  		return nil, fmt.Errorf("unsupported signature version: %d", sig.Version)
    67  	}
    68  	if string(sig.MagicHeader[:]) != magicHeader {
    69  		return nil, fmt.Errorf("invalid magic header: %s", sig.MagicHeader[:])
    70  	}
    71  	if sig.Namespace != "file" {
    72  		return nil, fmt.Errorf("invalid signature namespace: %s", sig.Namespace)
    73  	}
    74  	if _, ok := supportedHashAlgorithms[sig.HashAlgorithm]; !ok {
    75  		return nil, fmt.Errorf("unsupported hash algorithm: %s", sig.HashAlgorithm)
    76  	}
    77  
    78  	// Now we can unpack the Signature and PublicKey blocks
    79  	sshSig := ssh.Signature{}
    80  	if err := ssh.Unmarshal([]byte(sig.Signature), &sshSig); err != nil {
    81  		return nil, err
    82  	}
    83  	// TODO: check the format here (should be rsa-sha512)
    84  
    85  	pk, err := ssh.ParsePublicKey([]byte(sig.PublicKey))
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	return &Signature{
    91  		signature: &sshSig,
    92  		pk:        pk,
    93  		hashAlg:   sig.HashAlgorithm,
    94  	}, nil
    95  }
    96  

View as plain text