Go: x/crypto/ssh: cannot sign certificate with different algorithm

Created on 24 Dec 2019  路  4Comments  路  Source: golang/go

What version of Go are you using (go version)?

$ go version
go version go1.13.4 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output

$ go env
not relevant

What did you do?

I want to be able to change the algorithm used when signing an SSH certificate. Specifically with a private key implemented in hardware with ssh.NewSignerFromSigner.

What did you expect to see?

I should be able to pass an AlgorithmSigner interface, and specify which algorithm to use when invoking Certificate.SignCert

https://github.com/golang/crypto/blob/0a08dada0ff98d02f3864a23ae8d27cb8fba5303/ssh/certs.go#L417-L432

What did you see instead?

When signing a certificate with Certificate.SignCert I can not specify the algorithm used.

I am happy to contribute a change to fix this. I propose adding a new method to the Certificate struct, named SignCertWithAlgorithm which correctly calls authority.SignWithAlgorithm.

I've put together a short proof-of-concept implementing SignCertWithAlgorithm and adding a new private method prepareForSigning to keep the nonce generation in once place.

https://play.golang.org/p/PYbYu6-9XY8

NeedsInvestigation

Most helpful comment

A particular urgency for this issue is that right now with an RSA private key, the default is SHA-1. OpenSSH 8.2 has removed support for RSA-SHA1 signatures on certificates: https://www.openssh.com/txt/release-8.2

All 4 comments

/cc @katiehockman @FiloSottile

/cc @hanwen

An alternative implementation would be to create a NewAlgorithmSignerFromSigner method to return a signer interface, that can sign with a particular algorithm. Then you could pass it to Certificate.SignCert normally.

https://play.golang.org/p/lywpKtapMeZ

type sshAlgorithmSigner struct {
    algorithm string
    signer    ssh.AlgorithmSigner
}

func (s *sshAlgorithmSigner) PublicKey() ssh.PublicKey {
    return s.signer.PublicKey()
}

func (s *sshAlgorithmSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) {
    return s.signer.SignWithAlgorithm(rand, data, s.algorithm)
}

func NewAlgorithmSignerFromSigner(signer crypto.Signer, algorithm string) (ssh.Signer, error) {
    sshSigner, err := ssh.NewSignerFromSigner(signer)
    if err != nil {
        return nil, err
    }
    algorithmSigner, ok := sshSigner.(ssh.AlgorithmSigner)
    if !ok {
        return nil, errors.New("unable to cast to ssh.AlgorithmSigner")
    }
    s := sshAlgorithmSigner{
        signer:    algorithmSigner,
        algorithm: algorithm,
    }
    return &s, nil
}

A particular urgency for this issue is that right now with an RSA private key, the default is SHA-1. OpenSSH 8.2 has removed support for RSA-SHA1 signatures on certificates: https://www.openssh.com/txt/release-8.2

Was this page helpful?
0 / 5 - 0 ratings

Related issues

natefinch picture natefinch  路  3Comments

longzhizhi picture longzhizhi  路  3Comments

mingrammer picture mingrammer  路  3Comments

michaelsafyan picture michaelsafyan  路  3Comments

ashb picture ashb  路  3Comments