...

Source file src/github.com/sigstore/rekor/pkg/pki/ssh/sign.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  	"crypto/rand"
    20  	"crypto/sha256"
    21  	"crypto/sha512"
    22  	"hash"
    23  	"io"
    24  
    25  	"golang.org/x/crypto/ssh"
    26  )
    27  
    28  // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L81
    29  type MessageWrapper struct {
    30  	Namespace     string
    31  	Reserved      string
    32  	HashAlgorithm string
    33  	Hash          string
    34  }
    35  
    36  // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L34
    37  type WrappedSig struct {
    38  	MagicHeader   [6]byte
    39  	Version       uint32
    40  	PublicKey     string
    41  	Namespace     string
    42  	Reserved      string
    43  	HashAlgorithm string
    44  	Signature     string
    45  }
    46  
    47  const (
    48  	magicHeader          = "SSHSIG"
    49  	defaultHashAlgorithm = "sha512"
    50  )
    51  
    52  var supportedHashAlgorithms = map[string]func() hash.Hash{
    53  	"sha256": sha256.New,
    54  	"sha512": sha512.New,
    55  }
    56  
    57  func sign(s ssh.AlgorithmSigner, m io.Reader) (*ssh.Signature, error) {
    58  	hf := sha512.New()
    59  	if _, err := io.Copy(hf, m); err != nil {
    60  		return nil, err
    61  	}
    62  	mh := hf.Sum(nil)
    63  
    64  	sp := MessageWrapper{
    65  		Namespace:     "file",
    66  		HashAlgorithm: defaultHashAlgorithm,
    67  		Hash:          string(mh),
    68  	}
    69  
    70  	dataMessageWrapper := ssh.Marshal(sp)
    71  	dataMessageWrapper = append([]byte(magicHeader), dataMessageWrapper...)
    72  
    73  	// ssh-rsa is not supported for RSA keys:
    74  	// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L71
    75  	// We can use the default value of "" for other key types though.
    76  	algo := ""
    77  	if s.PublicKey().Type() == ssh.KeyAlgoRSA {
    78  		algo = ssh.KeyAlgoRSASHA512
    79  	}
    80  	sig, err := s.SignWithAlgorithm(rand.Reader, dataMessageWrapper, algo)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	return sig, nil
    85  }
    86  
    87  func Sign(sshPrivateKey string, data io.Reader) ([]byte, error) {
    88  	s, err := ssh.ParsePrivateKey([]byte(sshPrivateKey))
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	as, ok := s.(ssh.AlgorithmSigner)
    94  	if !ok {
    95  		return nil, err
    96  	}
    97  
    98  	sig, err := sign(as, data)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	armored := Armor(sig, s.PublicKey())
   104  	return armored, nil
   105  }
   106  

View as plain text