From b0ae23a0aad80b8587036ece8a621884d59c000b Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 15 Sep 2024 13:30:47 +0000 Subject: design/68723-crypto-ssh-v2.md: PrivateKeySigner and MarshalPrivateKey Options PrivateKeySigner is a Signer that can also return the associated crypto.Signer. This means ParseRawPrivateKey and ParseRawPrivateKeyWithPassphrase can be private now. MarshalPrivateKeyOptions defines the options to Marshal a private key in OpenSSH format. We can pass the passphrase as option to MarshalPrivateKey and so we don't need MarshalPrivateKeyWithPassphrase. Additionally we can also configure the salt rounds that is currently hard coded (see golang/go#68700) and easly add more options in the future. Change-Id: Id5c30f69fc600d19ef579aa2cf54dc8620677bb8 GitHub-Last-Rev: 98ee61e445108a76c35ce3493bc5f2662c4c28ca GitHub-Pull-Request: golang/proposal#52 Reviewed-on: https://go-review.googlesource.com/c/proposal/+/613036 Commit-Queue: Nicola Murino Reviewed-by: Nicola Murino Auto-Submit: Nicola Murino --- design/68723-crypto-ssh-v2.md | 41 ++++++++++++++++++++++++ design/68723/ssh.html | 74 ++++++++++++++++++++++++------------------- 2 files changed, 83 insertions(+), 32 deletions(-) diff --git a/design/68723-crypto-ssh-v2.md b/design/68723-crypto-ssh-v2.md index e1b2957..8827f14 100644 --- a/design/68723-crypto-ssh-v2.md +++ b/design/68723-crypto-ssh-v2.md @@ -379,6 +379,47 @@ type ExtendedAgent interface { } ``` +### Add PrivateKeySigner + +`PrivateKeySigner` is a `Signer` that can also return the associated `crypto.Signer`. +This means `ParseRawPrivateKey` and `ParseRawPrivateKeyWithPassphrase` can be private now because `ParsePrivateKey` and `ParsePrivateKeyWithPassphrase` return both a `Signer` and a `crypto.Signer`. + +```go +// PrivateKeySigner is a [ssh.Signer] that can also return the associated +// [crypto.Signer]. +type PrivateKeySigner struct { + Signer +} + +func (k *PrivateKeySigner) CryptoSigner() crypto.Signer + +func ParsePrivateKey(pemBytes []byte) (*PrivateKeySigner, error) + +func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (*PrivateKeySigner, error) +``` + +### Add MarshalPrivateKeyOptions + +Instead of passing options as function parameters to `MarshalPrivateKey` add a struct for options. + +```go +// MarshalPrivateKeyOptions defines the available options to Marshal a private +// key in OpenSSH format. +type MarshalPrivateKeyOptions struct { + Comment string + Passphrase string + SaltRounds int +} +``` + +And change `MarshalPrivateKey` like this. + +```go +func MarshalPrivateKey(key crypto.PrivateKey, options MarshalPrivateKeyOptions) (*pem.Block, error) +``` + +This way we can remove `MarshalPrivateKeyWithPassphrase` because the passphrase is now an option. We can easily add support for other options, for example making salt rounds confgurable, see [golang/go#68700](https://github.com/golang/go/issues/68700). + ### Deprecated API and algorithms removal We'll remove DSA support, see [here](https://lists.mindrot.org/pipermail/openssh-unix-announce/2024-January/000156.html) for DSA status in OpenSSH, it is already disabled by default and will be removed in January, 2025. diff --git a/design/68723/ssh.html b/design/68723/ssh.html index c079e1a..ff90f86 100644 --- a/design/68723/ssh.html +++ b/design/68723/ssh.html @@ -573,10 +573,7 @@ so its API may be changed when pressing needs arise.
  • func FingerprintSHA256(pubKey PublicKey) string
  • func Marshal(msg interface{}) []byte
  • func MarshalAuthorizedKey(key PublicKey) []byte
  • -
  • func MarshalPrivateKey(key crypto.PrivateKey, comment string) (*pem.Block, error)
  • -
  • func MarshalPrivateKeyWithPassphrase(key crypto.PrivateKey, comment string, passphrase []byte) (*pem.Block, error)
  • -
  • func ParseRawPrivateKey(pemBytes []byte) (crypto.Signer, error)
  • -
  • func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (crypto.Signer, error)
  • +
  • func MarshalPrivateKey(key crypto.PrivateKey, options MarshalPrivateKeyOptions) (*pem.Block, error)
  • func Unmarshal(data []byte, out interface{}) error
  • type Algorithms @@ -736,6 +733,9 @@ so its API may be changed when pressing needs arise.
  • type KeyboardInteractiveChallenge
  • +
  • + type MarshalPrivateKeyOptions +
  • type NewChannel
      @@ -766,6 +766,14 @@ so its API may be changed when pressing needs arise.
    • type Permissions
    • +
    • + type PrivateKeySigner + +
    • type PublicKey
    • @@ -1068,23 +1074,9 @@ number is prepended to the result. If the last of member has the

      MarshalAuthorizedKey serializes key for inclusion in an OpenSSH authorized_keys file. The return value ends with newline.

      func MarshalPrivateKey

      -
      func MarshalPrivateKey(key crypto.PrivateKey, comment string) (*pem.Block, error)
      +
      func MarshalPrivateKey(key crypto.PrivateKey, options MarshalPrivateKeyOptions) (*pem.Block, error)

      MarshalPrivateKey returns a PEM block with the private key serialized in the OpenSSH format. -

      func MarshalPrivateKeyWithPassphrase

      -
      func MarshalPrivateKeyWithPassphrase(key crypto.PrivateKey, comment string, passphrase []byte) (*pem.Block, error)
      -

      MarshalPrivateKeyWithPassphrase returns a PEM block holding the encrypted -private key serialized in the OpenSSH format. -

      func ParseRawPrivateKey

      -
      func ParseRawPrivateKey(pemBytes []byte) (crypto.Signer, error)
      -

      ParseRawPrivateKey returns a private key from a PEM encoded private key. It supports -RSA, ECDSA, and Ed25519 private keys in PKCS#1, PKCS#8, OpenSSL, and OpenSSH -formats. If the private key is encrypted, it will return a PassphraseMissingError. -

      func ParseRawPrivateKeyWithPassphrase

      -
      func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (crypto.Signer, error)
      -

      ParseRawPrivateKeyWithPassphrase returns a private key decrypted with -passphrase from a PEM encoded private key. If the passphrase is wrong, it -will return x509.IncorrectPasswordError.

      func Unmarshal

      func Unmarshal(data []byte, out interface{}) error

      Unmarshal parses data in SSH wire format into a structure. The out @@ -1860,6 +1852,14 @@ successful authentication, the server may send a challenge with no questions, for which the name and instruction messages should be printed. RFC 4256 section 3.3 details how the UI should behave for both CLI and GUI environments. +

      type MarshalPrivateKeyOptions

      +
      type MarshalPrivateKeyOptions struct {
      +	Comment    string
      +	Passphrase string
      +	SaltRounds int
      +}
      +

      MarshalPrivateKeyOptions defines the available options to Marshal a private +key in OpenSSH format.

      type NewChannel

      type NewChannel struct {
       	// contains filtered or unexported fields
      @@ -1945,7 +1945,27 @@ specific to a user or a specific authentication method for a user.
       The Permissions value for a successful authentication attempt is
       available in ServerConn, so it can be used to pass information from
       the user-authentication phase to the application layer.
      -

      type PublicKey

      +

      type PrivateKeySigner

      +
      type PrivateKeySigner struct {
      +	Signer
      +	// contains filtered or unexported fields
      +}
      +

      PrivateKeySigner is a ssh.Signer that can also return the associated +crypto.Signer. +

      func ParsePrivateKey

      +
      func ParsePrivateKey(pemBytes []byte) (*PrivateKeySigner, error)
      +

      ParsePrivateKey returns a ssh.PrivateKeySigner from a PEM encoded private +key. It supports RSA, ECDSA, and Ed25519 private keys in PKCS#1, PKCS#8, +OpenSSL, and OpenSSH formats. If the private key is encrypted, it will return +a PassphraseMissingError. +

      func ParsePrivateKeyWithPassphrase

      +
      func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (*PrivateKeySigner, error)
      +

      ParsePrivateKeyWithPassphrase returns a ssh.PrivateKeySigner from a PEM +encoded private key and passphrase. It supports the same keys as +ssh.ParsePrivateKey. +

      func (*PrivateKeySigner) CryptoSigner

      +
      func (k *PrivateKeySigner) CryptoSigner() crypto.Signer
      +

      type PublicKey

      type PublicKey interface {
       	// Type returns the key format name, e.g. "ssh-rsa".
       	Type() string
      @@ -2713,16 +2733,6 @@ modules.
       algorithms. The algorithms must be set in preference order. The list must not
       be empty, and it must not include certificate types. An error is returned if
       the specified algorithms are incompatible with the public key type.
      -

      func ParsePrivateKey

      -
      func ParsePrivateKey(pemBytes []byte) (Signer, error)
      -

      ParsePrivateKey returns a Signer from a PEM encoded private key. It supports -the same keys as ParseRawPrivateKey. If the private key is encrypted, it -will return a PassphraseMissingError. -

      func ParsePrivateKeyWithPassphrase

      -
      func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (Signer, error)
      -

      ParsePrivateKeyWithPassphrase returns a Signer from a PEM encoded private -key and passphrase. It supports the same keys as -ParseRawPrivateKeyWithPassphrase.

      type TerminalModes

      type TerminalModes map[uint8]uint32

      type Waitmsg

      -- cgit v1.3