ssh: add MultiAlgorithmSigner

MultiAlgorithmSigner allows to restrict client-side, server-side and
certificate signing algorithms.

Fixes golang/go#52132
Fixes golang/go#36261

Change-Id: I295092f1bba647327aaaf294f110e9157d294159
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/508398
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Nicola Murino
2023-09-20 18:10:30 +00:00
committed by Gopher Robot
parent 3f0842a464
commit 28c53ff63c
9 changed files with 554 additions and 66 deletions
+67 -1
View File
@@ -7,6 +7,8 @@ package ssh_test
import (
"bufio"
"bytes"
"crypto/rand"
"crypto/rsa"
"fmt"
"log"
"net"
@@ -75,7 +77,6 @@ func ExampleNewServerConn() {
if err != nil {
log.Fatal("Failed to parse private key: ", err)
}
config.AddHostKey(private)
// Once a ServerConfig has been configured, connections can be
@@ -139,6 +140,36 @@ func ExampleNewServerConn() {
}
}
func ExampleServerConfig_AddHostKey() {
// Minimal ServerConfig supporting only password authentication.
config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
// Should use constant-time compare (or better, salt+hash) in
// a production setting.
if c.User() == "testuser" && string(pass) == "tiger" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
}
privateBytes, err := os.ReadFile("id_rsa")
if err != nil {
log.Fatal("Failed to load private key: ", err)
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
log.Fatal("Failed to parse private key: ", err)
}
// Restrict host key algorithms to disable ssh-rsa.
signer, err := ssh.NewSignerWithAlgorithms(private.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256, ssh.KeyAlgoRSASHA512})
if err != nil {
log.Fatal("Failed to create private key with restricted algorithms: ", err)
}
config.AddHostKey(signer)
}
func ExampleClientConfig_HostKeyCallback() {
// Every client must provide a host key check. Here is a
// simple-minded parse of OpenSSH's known_hosts file
@@ -318,3 +349,38 @@ func ExampleSession_RequestPty() {
log.Fatal("failed to start shell: ", err)
}
}
func ExampleCertificate_SignCert() {
// Sign a certificate with a specific algorithm.
privateKey, err := rsa.GenerateKey(rand.Reader, 3072)
if err != nil {
log.Fatal("unable to generate RSA key: ", err)
}
publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
log.Fatal("unable to get RSA public key: ", err)
}
caKey, err := rsa.GenerateKey(rand.Reader, 3072)
if err != nil {
log.Fatal("unable to generate CA key: ", err)
}
signer, err := ssh.NewSignerFromKey(caKey)
if err != nil {
log.Fatal("unable to generate signer from key: ", err)
}
mas, err := ssh.NewSignerWithAlgorithms(signer.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256})
if err != nil {
log.Fatal("unable to create signer with algoritms: ", err)
}
certificate := ssh.Certificate{
Key: publicKey,
CertType: ssh.UserCert,
}
if err := certificate.SignCert(rand.Reader, mas); err != nil {
log.Fatal("unable to sign certificate: ", err)
}
// Save the public key to a file and check that rsa-sha-256 is used for
// signing:
// ssh-keygen -L -f <path to the file>
fmt.Println(string(ssh.MarshalAuthorizedKey(&certificate)))
}