mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-24 16:17:11 +08:00
tsh: Also create a PuTTY PPK-formatted keypair on login (#12733)
PuTTY uses its own keypair format which has the extension .ppk on Windows, hence PPK. The specification for the file format is here: https://the.earth.li/\~sgtatham/putty/0.76/htmldoc/AppendixC.html\#ppk
This commit is contained in:
@@ -234,6 +234,7 @@ func writeProfile(t *testing.T, p *profile.Profile) {
|
||||
require.NoError(t, os.WriteFile(p.KnownHostsPath(), sshCACert, 0600))
|
||||
require.NoError(t, os.MkdirAll(p.SSHDir(), 0700))
|
||||
require.NoError(t, os.WriteFile(p.SSHCertPath(), sshCert, 0600))
|
||||
require.NoError(t, os.WriteFile(p.PPKFilePath(), ppkFile, 0600))
|
||||
}
|
||||
|
||||
func getExpectedTLSConfig(t *testing.T) *tls.Config {
|
||||
@@ -347,4 +348,31 @@ Na6B0YR7mdrrL+lyzymnOr6UOrT5nUWRAB1QeY7dhBNnsvoZwaS3VLSc1KCk
|
||||
sshCert = []byte("ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg8C10PShw+GxCadSlC4nFURIAyvDtgWRvHPabpL5wzDQAAAADAQABAAABAQDORRWgniufZcCLYcl4EgjGWx0w8bMuugm5v14cBWykC54MktKCpB24dOiDTVH0wABGhZTBtAs3QMhskUrvRSvARNdu5ERwbOoW9aU4Mtn+kxZBaP4eFk1luBkEojvAJewNrbkY3N5gJ5O9avpL6UGEu7Z5IZhQmBPIysTLZWBt/ceJEOm7ZZez/cyOl2b+UUa5c6gA7sGaRHC2FYtE4yE6j28d6w2U+JfhJrJYWqBvsROVbvhmFy5b8AfRP2pnzdWfSqbODm+iccbHvZI3jIq/ZsIjZAVlcoR/yxEwwPV2urE0Nnu+TGDO8lyS2DpgSleINe+kH9U9cnu2vxoJ+LdlAAAAAAAAAAAAAAABAAAADGFjY2Vzcy1hZG1pbgAAABAAAAAMYWNjZXNzLWFkbWluAAAAAGAtfCkAAAAAYC4lJQAAAAAAAACdAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnRlbGVwb3J0LXJvbGVzAAAALQAAACl7InZlcnNpb24iOiJ2MSIsInJvbGVzIjpbImFjY2Vzcy1hZG1pbiJdfQAAAA90ZWxlcG9ydC10cmFpdHMAAAATAAAAD3sibG9naW5zIjpudWxsfQAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQD3VbuNmR0h3tjYIkTVG+HfNByigp6tuNl8XVylIWx7a7ojRA1nJVzAtNs9QQMut8XY+7jxf4Ue83eIaE0e0QKA0GZlRdbSG0zaYzK8CDAcPVN6Ywt8jnGKuuMhBAckGkN/9nyuJHgTAKeHYgdgQgijPuW/D59s3Sk3vCRHryZzJfZDQ52i40B1q2zLvCcQa6UBvPblHAF3usRa08DnsNkgLey1EkkyvBazqt1amH2Epl3uJRHHUtRVSp2a+0597leT58RZNFfFfB9pccPJfD7cn+iiDmN62T/8YslLYl/O6xCJ43Or7wIRHwJ1tY5hq/Bw7LYn29zeBrIkxIvsH8WtAAABFAAAAAxyc2Etc2hhMi01MTIAAAEAhIz0X+wgA0B8Bi67ALpTEA3kHVWaQY3aT+Ig8obof9upq51H0YlySPJph8h6pVzfSJzQYtuGbmzQ/XAGRMn541mnSUGoy0WCHzscyCowaj9VgjFyVpct7Nz98dB3PnRocNTajGGla+AteZEU3d6KXv/CaA4NGwO3k0rYB+UfX0AAaatAwwxnzYehpCvwSqPdrq/OIyb0aljZHADoNRrcnmYDbB1V76WWY6eTCxYGXx1QyU4A8kH9U8pIZ1fVif/i8dSTbBTftTtv5bmO4WUbVscRw/xIqgZ8v6StNLGHPTt/+Zn+iUoiIrwcnpy+yQp2SRTv7+Lg2SSvJO818x3NNg==")
|
||||
|
||||
sshCACert = []byte("@cert-authority *.example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMIgxZpT5362npj0x6NQA76IB73bcK85K8cEyKURuHtFC83RjBzvzqtUz6X02+6ohVZiR2MdmsXkCLznzwEIZ0NtoxgnLTZLmduPLeAuYW2vIFpd0G17y6Yog9vxhQ0BLdlhU5Y3JYjRYjmQMfe1iD/RXWD6rEvgWlz+c3HMQR33JqkVIEFH34upfkC2RQG3TXjMe5t14l3yCTtyF5YGzN7+6z/4+/EDto/F3zVtSEp+k8XE/m0ddTGo7usa8ErAom31RwrgkNRmgJmPleDwEflybEsgGKApJXkfFxmG2wu20JoEt/CFjY3fIIa/5aqIGJPpMH4aEdLcj/iyNCog8D type=host")
|
||||
|
||||
ppkFile = []byte(`PuTTY-User-Key-File-3: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: test.com
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDORRWgniufZcCLYcl4EgjGWx0w8bMuugm5
|
||||
v14cBWykC54MktKCpB24dOiDTVH0wABGhZTBtAs3QMhskUrvRSvARNdu5ERwbOoW
|
||||
9aU4Mtn+kxZBaP4eFk1luBkEojvAJewNrbkY3N5gJ5O9avpL6UGEu7Z5IZhQmBPI
|
||||
ysTLZWBt/ceJEOm7ZZez/cyOl2b+UUa5c6gA7sGaRHC2FYtE4yE6j28d6w2U+Jfh
|
||||
JrJYWqBvsROVbvhmFy5b8AfRP2pnzdWfSqbODm+iccbHvZI3jIq/ZsIjZAVlcoR/
|
||||
yxEwwPV2urE0Nnu+TGDO8lyS2DpgSleINe+kH9U9cnu2vxoJ+Ld
|
||||
Private-Lines: 14
|
||||
AAABAE1Vk207wAksAgt/5yQwRr/vizs9czuSnnDYsbT5x6idfm0iYvB+DXKJyl7o
|
||||
D1Ee5zuJe6NAGHBnxn0F4D1jBqs4ZDj8NjicbQucn4w5bIfIp7BwZ83p+KypYB/f
|
||||
n11EGoNqXZpXvLv6Oqbqw9rQIjNcmWZC1TNqQQioFS5Y3NV/gw5uYCRXZlSLMsRC
|
||||
vcX2+LN2EP76ZbkpIVpTCidC2TxwFPPbyMsG774Olfz4U2IDgX1mO+milF7RIa/v
|
||||
PADSeHAX6tJHmZ13GsyP0GAdPbFa0Ls/uykeGi1uGPFkdkNEqbWlDf1Z9IG0dr/c
|
||||
k2eh8G2X8E+VFgzsKp4kWtH9nGEAAACBAOQgKFCPDVQPRqgCX7O4ZBh0MKV9V9fi
|
||||
aRYReHWSrFeNDUXqmitL3f5lk2I5TDjzuqKJaz6Ag1JUGFOqaCA7RJ3yeipGLizI
|
||||
MWSp0tjpQ7YSqGSXvWlEwj9UYU1R8sgAUV2xoLTTChWJGd/AvfiTPl+U9HimUx3i
|
||||
vsI4mXeefrJtAAAAgQDneUWh0uIpCNBHsihSYan4/qqesPA51TVF9P2Ox7fnE5v2
|
||||
1i9mzdeRRdT4wQYAxbU++ajW/3E6Nlt0VgH0j+0hhNLKNhA1oWOAkw8wtLHaqMzO
|
||||
EVcBjl/y3bT8IG3ZXWrjppry1HaWX/9C9jiaq8lRpoHSmS5qwVsoxclwYp292QAA
|
||||
AIBV1ZA8WqvC+xZrPwmtmN87BHwGjqpE52kbUfcD94k8IqqhPR9oN9uOlcoBzZiS
|
||||
3SkunUpmzKlcXe63RQYOEqEVlTNOafcYNc5gW8NXKrgF7vBE91VsfmOGJvLt3pIv
|
||||
k53lH1qmEOm9+vrhNwNzpHk4AqDkP+0YDG++B4n0BtJJpw==
|
||||
Private-MAC: 8951bbe929e0714a61df01bc8fbc5223e3688f174aee29339931984fb9224c7d`)
|
||||
)
|
||||
|
||||
@@ -131,6 +131,9 @@ const (
|
||||
|
||||
// DatabaseCAMinVersion is the minimum Teleport version that supports Database Certificate Authority.
|
||||
DatabaseCAMinVersion = "10.0.0"
|
||||
|
||||
// SSHRSAType is the string which specifies an "ssh-rsa" formatted keypair
|
||||
SSHRSAType = "ssh-rsa"
|
||||
)
|
||||
|
||||
// SystemConnectors lists the names of the system-reserved connectors.
|
||||
|
||||
@@ -407,6 +407,11 @@ func (p *Profile) SSHCertPath() string {
|
||||
return keypaths.SSHCertPath(p.Dir, p.Name(), p.Username, p.SiteName)
|
||||
}
|
||||
|
||||
// PPKFilePath returns the path to the profile's PuTTY PPK-formatted keypair.
|
||||
func (p *Profile) PPKFilePath() string {
|
||||
return keypaths.PPKFilePath(p.Dir, p.Name(), p.Username)
|
||||
}
|
||||
|
||||
// KnownHostsPath returns the path to the profile's ssh certificate authorities.
|
||||
func (p *Profile) KnownHostsPath() string {
|
||||
return keypaths.KnownHostsPath(p.Dir)
|
||||
|
||||
@@ -38,6 +38,8 @@ const (
|
||||
fileNameTLSCerts = "certs.pem"
|
||||
// fileExtCert is the suffix/extension of a file where an SSH Cert is stored.
|
||||
fileExtSSHCert = "-cert.pub"
|
||||
// fileExtPPK is the suffix/extension of a file where an SSH keypair is stored in PuTTY PPK format.
|
||||
fileExtPPK = ".ppk"
|
||||
// fileExtPub is the extension of a file where a public key is stored.
|
||||
fileExtPub = ".pub"
|
||||
// fileExtLocalCA is the extension of a file where a self-signed localhost CA cert is stored.
|
||||
@@ -64,6 +66,7 @@ const (
|
||||
// │ ├── certs.pem --> TLS CA certs for the Teleport CA
|
||||
// │ ├── foo --> RSA Private Key for user "foo"
|
||||
// │ ├── foo.pub --> Public Key
|
||||
// │ ├── foo.ppk --> PuTTY PPK-formatted keypair for user "foo"
|
||||
// │ ├── foo-x509.pem --> TLS client certificate for Auth Server
|
||||
// │ ├── foo-ssh --> SSH certs for user "foo"
|
||||
// │ │ ├── root-cert.pub --> SSH cert for Teleport cluster "root"
|
||||
@@ -171,6 +174,14 @@ func SSHDir(baseDir, proxy, username string) string {
|
||||
return filepath.Join(ProxyKeyDir(baseDir, proxy), username+sshDirSuffix)
|
||||
}
|
||||
|
||||
// PPKFilePath returns the path to the user's PuTTY PPK-formatted keypair
|
||||
// for the given proxy and cluster.
|
||||
//
|
||||
// <baseDir>/keys/<proxy>/<username>.ppk
|
||||
func PPKFilePath(baseDir, proxy, username string) string {
|
||||
return filepath.Join(ProxyKeyDir(baseDir, proxy), username+fileExtPPK)
|
||||
}
|
||||
|
||||
// SSHCertPath returns the path to the users's SSH certificate
|
||||
// for the given proxy and cluster.
|
||||
//
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
Copyright 2021 Gravitational, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package ppk provides functions implementing conversion between Teleport's native RSA
|
||||
// keypairs and PuTTY's PPK format. It also provides functions for working with RFC4251-formatted
|
||||
// mpints and strings.
|
||||
package ppk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/gravitational/teleport/api/constants"
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
// ConvertToPPK takes a regular RSA-formatted keypair and converts it into the PPK file format used by the PuTTY SSH client.
|
||||
// The file format is described here: https://the.earth.li/~sgtatham/putty/0.76/htmldoc/AppendixC.html#ppk
|
||||
func ConvertToPPK(priv []byte, pub []byte) ([]byte, error) {
|
||||
// decode the private key from PEM format and extract the exponents
|
||||
privateKeyPemBlock, rest := pem.Decode(priv)
|
||||
if len(rest) > 0 {
|
||||
return nil, trace.Errorf("failed to decode private key, %v bytes left over", len(rest))
|
||||
}
|
||||
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes)
|
||||
if err != nil {
|
||||
return nil, trace.Errorf("failed to parse private key: %v", err)
|
||||
}
|
||||
|
||||
// https://the.earth.li/~sgtatham/putty/0.76/htmldoc/AppendixC.html#ppk
|
||||
// RSA keys are stored using an algorithm-name of 'ssh-rsa'. (Keys stored like this are also used by the updated RSA signature schemes that use
|
||||
// hashes other than SHA-1. The public key data has already provided the key modulus and the public encoding exponent. The private data stores:
|
||||
// mpint: the private decoding exponent of the key.
|
||||
// mpint: one prime factor p of the key.
|
||||
// mpint: the other prime factor q of the key. (RSA keys stored in this format are expected to have exactly two prime factors.)
|
||||
// mpint: the multiplicative inverse of q modulo p.
|
||||
ppkPrivateKey := new(bytes.Buffer)
|
||||
|
||||
// mpint: the private decoding exponent of the key.
|
||||
// this is known as 'D'
|
||||
binary.Write(ppkPrivateKey, binary.BigEndian, getRFC4251Mpint(privateKey.D))
|
||||
|
||||
// mpint: one prime factor p of the key.
|
||||
// this is known as 'P'
|
||||
// the RSA standard dictates that P > Q
|
||||
// for some reason what PuTTY names 'P' is Primes[1] to Go, and what PuTTY names 'Q' is Primes[0] to Go
|
||||
P, Q := privateKey.Primes[1], privateKey.Primes[0]
|
||||
binary.Write(ppkPrivateKey, binary.BigEndian, getRFC4251Mpint(P))
|
||||
|
||||
// mpint: the other prime factor q of the key. (RSA keys stored in this format are expected to have exactly two prime factors.)
|
||||
// this is known as 'Q'
|
||||
binary.Write(ppkPrivateKey, binary.BigEndian, getRFC4251Mpint(Q))
|
||||
|
||||
// mpint: the multiplicative inverse of q modulo p.
|
||||
// this is known as 'iqmp'
|
||||
iqmp := new(big.Int).ModInverse(Q, P)
|
||||
binary.Write(ppkPrivateKey, binary.BigEndian, getRFC4251Mpint(iqmp))
|
||||
|
||||
// now we need to base64-encode the PPK-formatted private key which is made up of the above values
|
||||
ppkPrivateKeyBase64 := make([]byte, base64.StdEncoding.EncodedLen(ppkPrivateKey.Len()))
|
||||
base64.StdEncoding.Encode(ppkPrivateKeyBase64, ppkPrivateKey.Bytes())
|
||||
|
||||
// read Teleport public key
|
||||
// fortunately, this is the one thing that's in exactly the same format that the PPK file uses, so we can just copy it verbatim
|
||||
// remove ssh-rsa plus additional space from beginning of string if present
|
||||
if !bytes.HasPrefix(pub, []byte(constants.SSHRSAType+" ")) {
|
||||
return nil, trace.BadParameter("pub does not appear to be an ssh-rsa public key")
|
||||
}
|
||||
pub = bytes.TrimSuffix(bytes.TrimPrefix(pub, []byte(constants.SSHRSAType+" ")), []byte("\n"))
|
||||
|
||||
// the PPK file contains an anti-tampering MAC which is made up of various values which appear in the file.
|
||||
// copied from Section C.3 of https://the.earth.li/~sgtatham/putty/0.76/htmldoc/AppendixC.html#ppk:
|
||||
// hex-mac-data is a hexadecimal-encoded value, 64 digits long (i.e. 32 bytes), generated using the HMAC-SHA-256 algorithm with the following binary data as input:
|
||||
// string: the algorithm-name header field.
|
||||
// string: the encryption-type header field.
|
||||
// string: the key-comment-string header field.
|
||||
// string: the binary public key data, as decoded from the base64 lines after the 'Public-Lines' header.
|
||||
// string: the plaintext of the binary private key data, as decoded from the base64 lines after the 'Private-Lines' header.
|
||||
|
||||
// these values are also used in the MAC generation, so we declare them as variables
|
||||
keyType := constants.SSHRSAType
|
||||
encryptionType := "none"
|
||||
// as work for the future, it'd be nice to get the proxy/user pair name in here to make the name more
|
||||
// of a unique identifier. this has to be done at generation time because the comment is part of the MAC
|
||||
fileComment := "teleport-generated-ppk"
|
||||
|
||||
// string: the algorithm-name header field.
|
||||
macKeyType := getRFC4251String([]byte(keyType))
|
||||
// create a buffer to hold the elements needed to generate the MAC
|
||||
macInput := new(bytes.Buffer)
|
||||
binary.Write(macInput, binary.LittleEndian, macKeyType)
|
||||
|
||||
// string: the encryption-type header field.
|
||||
macEncryptionType := getRFC4251String([]byte(encryptionType))
|
||||
binary.Write(macInput, binary.BigEndian, macEncryptionType)
|
||||
|
||||
// string: the key-comment-string header field.
|
||||
macComment := getRFC4251String([]byte(fileComment))
|
||||
binary.Write(macInput, binary.BigEndian, macComment)
|
||||
|
||||
// base64-decode the Teleport public key, as we need its binary representation to generate the MAC
|
||||
decoded := make([]byte, base64.StdEncoding.EncodedLen(len(pub)))
|
||||
n, err := base64.StdEncoding.Decode(decoded, pub)
|
||||
if err != nil {
|
||||
return nil, trace.Errorf("could not base64-decode public key: %v, got %v bytes successfully", err, n)
|
||||
}
|
||||
decoded = decoded[:n]
|
||||
// append the decoded public key bytes to the MAC buffer
|
||||
macPublicKeyData := getRFC4251String(decoded)
|
||||
binary.Write(macInput, binary.BigEndian, macPublicKeyData)
|
||||
|
||||
// append our PPK-formatted private key bytes to the MAC buffer
|
||||
macPrivateKeyData := getRFC4251String(ppkPrivateKey.Bytes())
|
||||
binary.Write(macInput, binary.BigEndian, macPrivateKeyData)
|
||||
|
||||
// as per the PPK spec, the key for the MAC is blank when the PPK file is unencrypted.
|
||||
// therefore, the key is a zero-length byte slice.
|
||||
hmacHash := hmac.New(sha256.New, []byte{})
|
||||
// generate the MAC using HMAC-SHA-256
|
||||
hmacHash.Write(macInput.Bytes())
|
||||
macString := hex.EncodeToString(hmacHash.Sum(nil))
|
||||
|
||||
// build the string-formatted output PPK file
|
||||
ppk := new(bytes.Buffer)
|
||||
fmt.Fprintf(ppk, "PuTTY-User-Key-File-3: %v\n", keyType)
|
||||
fmt.Fprintf(ppk, "Encryption: %v\n", encryptionType)
|
||||
fmt.Fprintf(ppk, "Comment: %v\n", fileComment)
|
||||
// chunk the Teleport-formatted public key into 64-character length lines
|
||||
chunkedPublicKey := chunk(string(pub), 64)
|
||||
fmt.Fprintf(ppk, "Public-Lines: %v\n", len(chunkedPublicKey))
|
||||
for _, r := range chunkedPublicKey {
|
||||
fmt.Fprintf(ppk, "%s\n", r)
|
||||
}
|
||||
// chunk the PPK-formatted private key into 64-character length lines
|
||||
chunkedPrivateKey := chunk(string(ppkPrivateKeyBase64), 64)
|
||||
fmt.Fprintf(ppk, "Private-Lines: %v\n", len(chunkedPrivateKey))
|
||||
for _, r := range chunkedPrivateKey {
|
||||
fmt.Fprintf(ppk, "%s\n", r)
|
||||
}
|
||||
fmt.Fprintf(ppk, "Private-MAC: %v\n", macString)
|
||||
|
||||
return ppk.Bytes(), nil
|
||||
}
|
||||
|
||||
// chunk converts a string into a []string with chunks of size chunkSize;
|
||||
// used to split base64-encoded strings across multiple lines with an even width.
|
||||
// note: this function operates on Unicode code points rather than bytes, therefore
|
||||
// using it with multi-byte characters will result in unevenly chunked strings.
|
||||
// it's intended usage is only for chunking base64-encoded strings.
|
||||
func chunk(s string, size int) []string {
|
||||
var chunks []string
|
||||
for b := []byte(s); len(b) > 0; {
|
||||
n := size
|
||||
if n > len(b) {
|
||||
n = len(b)
|
||||
}
|
||||
chunks = append(chunks, string(b[:n]))
|
||||
b = b[n:]
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
|
||||
// getRFC4251Mpint returns a stream of bytes representing a mixed-precision integer (a big.Int in Go)
|
||||
// prepended with a big-endian uint32 expressing the length of the data following.
|
||||
// This is the 'mpint' format in RFC4251 Section 5 (https://datatracker.ietf.org/doc/html/rfc4251#section-5)
|
||||
func getRFC4251Mpint(n *big.Int) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
b := n.Bytes()
|
||||
// RFC4251: If the most significant bit would be set for a positive number, the number MUST be preceded by a zero byte.
|
||||
if b[0]&0x80 > 0 {
|
||||
b = append([]byte{0}, b...)
|
||||
}
|
||||
// write a uint32 with the length of the byte stream to the buffer
|
||||
binary.Write(buf, binary.BigEndian, uint32(len(b)))
|
||||
// write the byte stream representing of the rest of the integer to the buffer
|
||||
binary.Write(buf, binary.BigEndian, b)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// getRFC4251String returns a stream of bytes representing a string prepended with a big-endian unit32
|
||||
// expressing the length of the data following.
|
||||
// This is the 'string' format in RFC4251 Section 5 (https://datatracker.ietf.org/doc/html/rfc4251#section-5)
|
||||
func getRFC4251String(data []byte) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
// write a uint32 with the length of the byte stream to the buffer
|
||||
binary.Write(buf, binary.BigEndian, uint32(len(data)))
|
||||
// write the byte stream representing of the rest of the data to the buffer
|
||||
for _, v := range data {
|
||||
binary.Write(buf, binary.BigEndian, v)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
Copyright 2022 Gravitational, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package ppk_test provides tests for the ppk package
|
||||
package ppk_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gravitational/teleport/api/utils/sshutils/ppk"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestConvertToPPK(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
priv []byte
|
||||
pub []byte
|
||||
output []byte
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "valid private and public keys 1",
|
||||
priv: []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA3U4OOAi+F1Ct1n8HZIs1P39CWB0mKLvshouuklenZug27SuI
|
||||
14rjE+hOTNHYz/Pkvk5mmKuIdegMCe8FHAF6chygcEC9BDkowLO+2+f3sazGsu4A
|
||||
9H4pDuUkuIM9MwmZV7A4TJ19rRAgha+6JKKR5KeEosfiLvAtOu2Pjqz8ZrOrUUqQ
|
||||
1AJ71SkWMPTJFksTNmgaH7a0SgJ4vVYMlYIAeyoAgqn6Qvu5Kez5ROfeKD4zys/+
|
||||
iFenrgbJrC38GNe2rxtb8/gfy03023FlPAQjGd1VLjxm8jhcJFqgM+uHTGRckgjv
|
||||
d+VIkCbvTwpPWvvZxQcRtk073P9G8xpiNz2qbwIDAQABAoIBAQCFv37obqA0BxaI
|
||||
5AzbvyZXUdoO1s8RH0I7rn+7Ai6yCvXnMMBrRA0pIuTvmIOoaoZ8XXW0HzdByxQ7
|
||||
jLFR07Lk9Fgif328566xh/B5hyAzyW/tA9qf6P93eRVQTkDWb561WFMuOqCRz4VY
|
||||
RnQBYB88SeHnX1Zbd9xeGOUCHZoNlrilVpgjscGcFNxyDP72qvI79z1vV+R6dhaf
|
||||
YI2v1D6aqx9qM988ytOokNi79wYvSUxqitz3IOD5nBd9ZNBC0fDeVmHqqbHSvLrr
|
||||
LouF7PiUuVA2LaWfVCy5dVtLkS16qbsfqzUA4B8Eg/oF0vPpJ7QMVxKI5j2//ScL
|
||||
lQ9h6gUBAoGBAOQ0t9gGuHKOMcp3H9C2fzNVbbWTubJoUyzFGyx+U2aJ4byRbxS3
|
||||
5d9cVu1GpS2ZgW6izCmxTG61Q0qQd4iT8e5cnFRU1Q3aK29TTK5hptthknXwKkVN
|
||||
vUtlYKRM3TPYeTJ3WMQCY/Lzm2uVhT2ZGkpu0NaA5qiWllyPm7HlyQA/AoGBAPhC
|
||||
KzioaPlqzwNKtHCsDSyeXsxU1aJCuMCIcgOB1yzmaaeL95CwMouMgouFyQ/CtLtO
|
||||
pQEjymGzVynwC15s1vh1nCOWlQCx6Cjs9ko9bmecqziyyWg94gn82yLU7gClQH6v
|
||||
+ezQ1n7/pb1DO/8dytO3+BZKSQH9lobzravGTcnRAoGAL8nKZfaiUXrtelSP2Qke
|
||||
ggV1v/x7epzWLh3ontylYmelWfOqq1AHV0ri+TU+CdqHfD+jOWfjdZuHx+mQ3oz8
|
||||
sMm8Avzw0MHLLrjm6e2RH4fDP+dXMsQgy9Ui88UU3XKLjsHnWMSXYZ0aAuGA0XFq
|
||||
TAQAv6qmos9GFYQNOqe/+8kCgYEAv88H69eae5J9bTKr5R3Zc+7MmZy2Do70hbUm
|
||||
OfV4lbVUTmJDHWQ1OUKPnlL4fJfX4Zwquo23kPLqVnmjnwoCsabUw15Vs1rBX9Vt
|
||||
mQCLq7wNQlpIaKTfXw4hFXFkjdUf1oIKXGEiSK8mk+s9kKepDRlnsXklnUcbpRri
|
||||
xQQLF/ECgYAmKBSQtPuyA9d3dAZj96HhYZzDjD2EtAhSUyx31vgqr8C7mmShQXLh
|
||||
kFap4eAldBxySXp/5af7H1Xf4BIfbbc1prMM1vIRFTN6l6rbircak7bb9a/dgWmX
|
||||
iukFsFq0G0Y2zt9oHOB7pKV/Kff4o1WQ0hcCBD6pZGhbsVxXBi4Oaw==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`),
|
||||
pub: []byte(`ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDdTg44CL4XUK3WfwdkizU/f0JYHSYou+yGi66SV6dm6DbtK4jXiuMT6E5M0djP8+S+TmaYq4h16AwJ7wUcAXpyHKBwQL0EOSjAs77b5/exrMay7gD0fikO5SS4gz0zCZlXsDhMnX2tECCFr7okopHkp4Six+Iu8C067Y+OrPxms6tRSpDUAnvVKRYw9MkWSxM2aBoftrRKAni9VgyVggB7KgCCqfpC+7kp7PlE594oPjPKz/6IV6euBsmsLfwY17avG1vz+B/LTfTbcWU8BCMZ3VUuPGbyOFwkWqAz64dMZFySCO935UiQJu9PCk9a+9nFBxG2TTvc/0bzGmI3Papv`),
|
||||
output: []byte(`PuTTY-User-Key-File-3: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: teleport-generated-ppk
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDdTg44CL4XUK3WfwdkizU/f0JYHSYou+yG
|
||||
i66SV6dm6DbtK4jXiuMT6E5M0djP8+S+TmaYq4h16AwJ7wUcAXpyHKBwQL0EOSjA
|
||||
s77b5/exrMay7gD0fikO5SS4gz0zCZlXsDhMnX2tECCFr7okopHkp4Six+Iu8C06
|
||||
7Y+OrPxms6tRSpDUAnvVKRYw9MkWSxM2aBoftrRKAni9VgyVggB7KgCCqfpC+7kp
|
||||
7PlE594oPjPKz/6IV6euBsmsLfwY17avG1vz+B/LTfTbcWU8BCMZ3VUuPGbyOFwk
|
||||
WqAz64dMZFySCO935UiQJu9PCk9a+9nFBxG2TTvc/0bzGmI3Papv
|
||||
Private-Lines: 14
|
||||
AAABAQCFv37obqA0BxaI5AzbvyZXUdoO1s8RH0I7rn+7Ai6yCvXnMMBrRA0pIuTv
|
||||
mIOoaoZ8XXW0HzdByxQ7jLFR07Lk9Fgif328566xh/B5hyAzyW/tA9qf6P93eRVQ
|
||||
TkDWb561WFMuOqCRz4VYRnQBYB88SeHnX1Zbd9xeGOUCHZoNlrilVpgjscGcFNxy
|
||||
DP72qvI79z1vV+R6dhafYI2v1D6aqx9qM988ytOokNi79wYvSUxqitz3IOD5nBd9
|
||||
ZNBC0fDeVmHqqbHSvLrrLouF7PiUuVA2LaWfVCy5dVtLkS16qbsfqzUA4B8Eg/oF
|
||||
0vPpJ7QMVxKI5j2//ScLlQ9h6gUBAAAAgQD4Qis4qGj5as8DSrRwrA0snl7MVNWi
|
||||
QrjAiHIDgdcs5mmni/eQsDKLjIKLhckPwrS7TqUBI8phs1cp8AtebNb4dZwjlpUA
|
||||
sego7PZKPW5nnKs4ssloPeIJ/Nsi1O4ApUB+r/ns0NZ+/6W9Qzv/HcrTt/gWSkkB
|
||||
/ZaG862rxk3J0QAAAIEA5DS32Aa4co4xyncf0LZ/M1VttZO5smhTLMUbLH5TZonh
|
||||
vJFvFLfl31xW7UalLZmBbqLMKbFMbrVDSpB3iJPx7lycVFTVDdorb1NMrmGm22GS
|
||||
dfAqRU29S2VgpEzdM9h5MndYxAJj8vOba5WFPZkaSm7Q1oDmqJaWXI+bseXJAD8A
|
||||
AACBAM6/w3llPMNA/ZRm8wIXXssPgAZCN79zYtVu6n4KMqBzi7qj1er4gzsLZpKS
|
||||
hpfdO/mDPhA3eFwU3XjYCKlHiJJYk53mc5sWwvbsfibAZSZAII/V4xWvRUUPE9EX
|
||||
INDa/8cd4YSy3PiZnUTNLVb2SmRFhnlB8ZBk3CyGEvcHskir
|
||||
Private-MAC: 2697903ac84b70273afc7adaa4e3ebb14536cdaf69654d40e3d46a5ba997ffb0
|
||||
`),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
desc: "valid private and public keys 2",
|
||||
priv: []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAve2um90K1SkpJD1vcjm2zUYUh5ZU7q1cmO7F0J/6MCEcq3vH
|
||||
fDPpPZ4uGLB9jPKzs6FYWhwFNW2oAsDvWSrwwxy5gl1dAdqp1wIm86gafShR0se5
|
||||
rSdhWKP40H2lHOysRC5Jr8cvVLgflvZ4PDMqr/63BKwwkT1vN2PuenYRAAIT77X9
|
||||
O0fumGQPKIxRGn5OPKEt1LzQ0+e/QlWrqZwzWDx5jqG3jbxibdcR/mHS60XdvusL
|
||||
UqxxWPjhVlDsKfvh2lt5sqsjulWW/GyNtlCfaTn2uu0nV8nbT2OvEO+oM/uyHos5
|
||||
7aIyePcOzCVM4dug6xJinqYTaVUsskKjPGUV6QIDAQABAoIBAQCBfis9k6DOIukt
|
||||
D0IL5DOxk2Vt6F5x+PsYPjva+SfwZrMQbC1fjlkpLM8LAFIpplRFVe1SSqZ2fhQ+
|
||||
BGNsLS3IKa6FprhCCl8f/BSoreWZjcLz7j63QxFJCUscg33u0aLGPbT5xtmLbpoD
|
||||
KHpjuRMSuZz475mRfQx1/IldL2B52sIAD6XRTgFoRG+mLu2iNVvuE0RVbASiyOUs
|
||||
lVwrGRI+5GuH8G6fDCJqpYzcm/S8VXmQc2jrbo/gQ76MkFxULqEMzadjN+XMXms7
|
||||
pGZLX6Hatubn1kmhl8l6+1GYLf1HVmWXoL+hgWwbfIn6WV9y/xpnoeoJfWcFLJli
|
||||
yABDx/mBAoGBAPhw3thyEP+5jdH2n1vz4X76yUbNJXaJGXozdoNfFKNOrYjFCLnD
|
||||
CzHJEQmDJoFCtF6TwgvFb90HNvtNLkbC81yotQ8rfDzNTlixUhycaSsCJBqw0loU
|
||||
wXoYQZiXpbfqT9Y7x7pwMxzRtkQYvyaowc7qF1xwJHhyCjDx38jAGnZxAoGBAMO1
|
||||
DXUpca09h+FujJkziyJStYq0YKqsuKXW7CuAq2iY70lzhv+SIPErqcYIWwi8JNv9
|
||||
EwBlEmSltFyGtxpeIVl6MJTil3vQ6eOSBCwt/E1YKvZoLv6mDf52Lc/wKtlecRPG
|
||||
Q7G2C1ioTD9lDiYysUDmkpfitiatFwEj+y606wL5AoGBAMlQJLM9Ets1D19QuWb4
|
||||
YwPS0aBGgZHgnD1yUBk5xW5jRajrCBwGmR6Zb+3GUUAyvhdZIccKEJAI1Zuiudnr
|
||||
BOpTZovJT92w+0hRP1khwPJxxLHAEGOgJ/r4hsbQMx+phVHylPBVFIXIxSm+5726
|
||||
x3kUJSPpVxQmTG3GwPBaAddxAoGALq+4QCTc22j8S0jl/X4QSOXWLPqOvOhrPBSj
|
||||
TlVpjpA9NRZ8M+eWODIkU/uWS+UmHdyndcamtp/ZAOGaOI4QApplkH7liEH0Kbeh
|
||||
izCFKaZIyXNdEp5mZDepAhvW/PfMnd0ENRaqakHrvovK7k3VfxgCDH2m2l8cR8df
|
||||
mmrKTXECgYEA300gTnT46pMU1Wr1Zq4vGauWzk3U4J9HUu3vNy+sg4EEZ9CoiNTw
|
||||
0a3f8u8gNQjB30koGW/5jYex3fUcnjTPqEGaiiGjI4oxMhquzqkVQ8FwnBAXJgT8
|
||||
nQVO8MZw8iFeSap0ILum8t60sp1/u9aCWJbjPtb/fhx0q7SLdjFEw8s=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`),
|
||||
pub: []byte(`ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC97a6b3QrVKSkkPW9yObbNRhSHllTurVyY7sXQn/owIRyre8d8M+k9ni4YsH2M8rOzoVhaHAU1bagCwO9ZKvDDHLmCXV0B2qnXAibzqBp9KFHSx7mtJ2FYo/jQfaUc7KxELkmvxy9UuB+W9ng8Myqv/rcErDCRPW83Y+56dhEAAhPvtf07R+6YZA8ojFEafk48oS3UvNDT579CVaupnDNYPHmOobeNvGJt1xH+YdLrRd2+6wtSrHFY+OFWUOwp++HaW3myqyO6VZb8bI22UJ9pOfa67SdXydtPY68Q76gz+7IeizntojJ49w7MJUzh26DrEmKephNpVSyyQqM8ZRXp`),
|
||||
output: []byte(`PuTTY-User-Key-File-3: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: teleport-generated-ppk
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQC97a6b3QrVKSkkPW9yObbNRhSHllTurVyY
|
||||
7sXQn/owIRyre8d8M+k9ni4YsH2M8rOzoVhaHAU1bagCwO9ZKvDDHLmCXV0B2qnX
|
||||
AibzqBp9KFHSx7mtJ2FYo/jQfaUc7KxELkmvxy9UuB+W9ng8Myqv/rcErDCRPW83
|
||||
Y+56dhEAAhPvtf07R+6YZA8ojFEafk48oS3UvNDT579CVaupnDNYPHmOobeNvGJt
|
||||
1xH+YdLrRd2+6wtSrHFY+OFWUOwp++HaW3myqyO6VZb8bI22UJ9pOfa67SdXydtP
|
||||
Y68Q76gz+7IeizntojJ49w7MJUzh26DrEmKephNpVSyyQqM8ZRXp
|
||||
Private-Lines: 14
|
||||
AAABAQCBfis9k6DOIuktD0IL5DOxk2Vt6F5x+PsYPjva+SfwZrMQbC1fjlkpLM8L
|
||||
AFIpplRFVe1SSqZ2fhQ+BGNsLS3IKa6FprhCCl8f/BSoreWZjcLz7j63QxFJCUsc
|
||||
g33u0aLGPbT5xtmLbpoDKHpjuRMSuZz475mRfQx1/IldL2B52sIAD6XRTgFoRG+m
|
||||
Lu2iNVvuE0RVbASiyOUslVwrGRI+5GuH8G6fDCJqpYzcm/S8VXmQc2jrbo/gQ76M
|
||||
kFxULqEMzadjN+XMXms7pGZLX6Hatubn1kmhl8l6+1GYLf1HVmWXoL+hgWwbfIn6
|
||||
WV9y/xpnoeoJfWcFLJliyABDx/mBAAAAgQDDtQ11KXGtPYfhboyZM4siUrWKtGCq
|
||||
rLil1uwrgKtomO9Jc4b/kiDxK6nGCFsIvCTb/RMAZRJkpbRchrcaXiFZejCU4pd7
|
||||
0OnjkgQsLfxNWCr2aC7+pg3+di3P8CrZXnETxkOxtgtYqEw/ZQ4mMrFA5pKX4rYm
|
||||
rRcBI/sutOsC+QAAAIEA+HDe2HIQ/7mN0fafW/PhfvrJRs0ldokZejN2g18Uo06t
|
||||
iMUIucMLMckRCYMmgUK0XpPCC8Vv3Qc2+00uRsLzXKi1Dyt8PM1OWLFSHJxpKwIk
|
||||
GrDSWhTBehhBmJelt+pP1jvHunAzHNG2RBi/JqjBzuoXXHAkeHIKMPHfyMAadnEA
|
||||
AACAE820IDiCymxsVqgmBSNJttApBaSl3ljTzWWeJQR7ksIm9kBvy30j1682v0yq
|
||||
RyPuY1EmQ3DJ3LqXbFq4qK12R/tALasyYyDYsJTt1xh+peFv23OSF8kDlG4MOdUp
|
||||
3WPivAMSPR0QR192Emb0caXEkyAhvQLHKGoi8/TgbfMG6Gc=
|
||||
Private-MAC: b5ede95d052e23815c8e8d816c758fb16370fc3178e1613fee61ec158900fd64
|
||||
`),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
desc: "valid public and private keys 3",
|
||||
priv: []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAz5J/f572H95c9DDZLrXT0kmjytznkvntSOjxmJM44fL8DQz2
|
||||
NINFi4awTNYD1eIIzaO4LLw+uXFWKD2P9LgtJ/Cxdb9LRi1OZ5Qrw/jj173zf/g+
|
||||
wpItjoakgAzerHxKAPj3DB8iHFfPq+3MfdY36SZHT0GOU7QIhnYULKWWuVfexx25
|
||||
VtgdGsmL9jwfAftzh00aCIej9zi2eSfGYfcIeRlSh9wvoYldrZbRvLTeMbW+YznW
|
||||
kH4W9taCGofrq/t8tN0beh9B7z2hMGxOLLnsxu3gQc2KIUqU5l1myL0rVncvSwZw
|
||||
ppQudZYtRyzmLOOm9PEvJHWvgu6KQBj5F24xrwIDAQABAoIBAQC0BgOMJMqjkxAd
|
||||
POxvhYUjoXhr7bDuGNKB5H38bNrto/aUPwSdQKilPPhUe1yyOCqYZwDJ06222aP2
|
||||
nIXooX+QX0EZtQHM6GhSjwByI78/kl/IQf30dCEMtpue7wqEn/ry4vooSiwkVsgm
|
||||
/cPX811kWS2JgHq2/7JRI8GVgzu4m/wLtOVUIUiSG/zNZWx/ThEvvE/528z5MZG5
|
||||
zGuQobHH+zfGYqk9IABcpNMH+4S353oPXAej2bCsQU6x+alM5z0fi+PuWIWtaDIb
|
||||
e/Va9WN2fghXF5lxu/+sCv8QkoPotbRfh0nLO0nTt4MUIFR0X/mVXbVWn+5SBhWC
|
||||
YUgcjychAoGBAOtLKKqkYzuOIyB2E3b7dPJ1XuzHOXj0Co5DoVNNs8TyEggoQPuj
|
||||
cTLUQaIN+M+MyNmtLi4GaF1dXRrJg7qZoJ681Vz0P+w+pso1UTQcja5G8iOwiKAD
|
||||
MIkyH9t9iW8yDN+J0dEzTqAgOPIDxkwDWuvwvsBleJ2EAV6qdecjLpIRAoGBAOHW
|
||||
0NGHYe4GCbt/gA5UVUYXehx9mckcLwyZJJThjTZXYr1kglRYa4de5YRMk9oPCHUu
|
||||
ODKqxL8CTcKyIijj1fJGDVcqTPFXlS4UZ31RLMvVnDaMID7V2zx+wxJ9onwhj798
|
||||
1k3fVahH2vXOFH9AogeHKDNyD1RdwDNOhBy95Me/AoGALV+bAf0dXbi1MWdTrZgk
|
||||
HzVfDs4EWTzGZFTKYWQUjKAZthT9IwmLpL+lwHhtSKjfeoqY4ys9KPP+JlJB4tQJ
|
||||
U1Ma2ggH46jZRRkvBZuT/s2TmCpMzn6O94YA+rSkshq2vMy491yrhtlv4cu0i6gB
|
||||
+om8XyGyNr3j/btlbSMtseECgYB66UL1Bk2SEc8yMI4tPlC6uQRIhUMxZRlmLeLu
|
||||
9GK6dIzUruMPrJ+5KTiY7GR7hTsBK4qCaNZzbnmLwQ8+WeGS3fVcvzTpFNWoIorA
|
||||
dXF/7l36ggD6scGEByl74syP6mQlv3eTIj2oPJM6vFIDf9WvayvB9A3LyMpWIiFc
|
||||
0yy0WQKBgQDCPCUvQhiOJyQ63n3pjFl5/YOtadl9KUD/CmdyUkCt69QoFgG0wTAV
|
||||
qalC9sysLQ1QI8A8GHNoNPjqMi7SWvzSgYN9TDRjS5GRlH13EALzP7AhWJWDoLYU
|
||||
9DXNAEQrPMtX4Lzre7FmrYqEYqwdcac+vyXVgDA7ti1LhDhj8mm3Sg==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`),
|
||||
pub: []byte(`ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDPkn9/nvYf3lz0MNkutdPSSaPK3OeS+e1I6PGYkzjh8vwNDPY0g0WLhrBM1gPV4gjNo7gsvD65cVYoPY/0uC0n8LF1v0tGLU5nlCvD+OPXvfN/+D7Cki2OhqSADN6sfEoA+PcMHyIcV8+r7cx91jfpJkdPQY5TtAiGdhQspZa5V97HHblW2B0ayYv2PB8B+3OHTRoIh6P3OLZ5J8Zh9wh5GVKH3C+hiV2tltG8tN4xtb5jOdaQfhb21oIah+ur+3y03Rt6H0HvPaEwbE4suezG7eBBzYohSpTmXWbIvStWdy9LBnCmlC51li1HLOYs46b08S8kda+C7opAGPkXbjGv`),
|
||||
output: []byte(`PuTTY-User-Key-File-3: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: teleport-generated-ppk
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDPkn9/nvYf3lz0MNkutdPSSaPK3OeS+e1I
|
||||
6PGYkzjh8vwNDPY0g0WLhrBM1gPV4gjNo7gsvD65cVYoPY/0uC0n8LF1v0tGLU5n
|
||||
lCvD+OPXvfN/+D7Cki2OhqSADN6sfEoA+PcMHyIcV8+r7cx91jfpJkdPQY5TtAiG
|
||||
dhQspZa5V97HHblW2B0ayYv2PB8B+3OHTRoIh6P3OLZ5J8Zh9wh5GVKH3C+hiV2t
|
||||
ltG8tN4xtb5jOdaQfhb21oIah+ur+3y03Rt6H0HvPaEwbE4suezG7eBBzYohSpTm
|
||||
XWbIvStWdy9LBnCmlC51li1HLOYs46b08S8kda+C7opAGPkXbjGv
|
||||
Private-Lines: 14
|
||||
AAABAQC0BgOMJMqjkxAdPOxvhYUjoXhr7bDuGNKB5H38bNrto/aUPwSdQKilPPhU
|
||||
e1yyOCqYZwDJ06222aP2nIXooX+QX0EZtQHM6GhSjwByI78/kl/IQf30dCEMtpue
|
||||
7wqEn/ry4vooSiwkVsgm/cPX811kWS2JgHq2/7JRI8GVgzu4m/wLtOVUIUiSG/zN
|
||||
ZWx/ThEvvE/528z5MZG5zGuQobHH+zfGYqk9IABcpNMH+4S353oPXAej2bCsQU6x
|
||||
+alM5z0fi+PuWIWtaDIbe/Va9WN2fghXF5lxu/+sCv8QkoPotbRfh0nLO0nTt4MU
|
||||
IFR0X/mVXbVWn+5SBhWCYUgcjychAAAAgQDh1tDRh2HuBgm7f4AOVFVGF3ocfZnJ
|
||||
HC8MmSSU4Y02V2K9ZIJUWGuHXuWETJPaDwh1LjgyqsS/Ak3CsiIo49XyRg1XKkzx
|
||||
V5UuFGd9USzL1Zw2jCA+1ds8fsMSfaJ8IY+/fNZN31WoR9r1zhR/QKIHhygzcg9U
|
||||
XcAzToQcveTHvwAAAIEA60soqqRjO44jIHYTdvt08nVe7Mc5ePQKjkOhU02zxPIS
|
||||
CChA+6NxMtRBog34z4zI2a0uLgZoXV1dGsmDupmgnrzVXPQ/7D6myjVRNByNrkby
|
||||
I7CIoAMwiTIf232JbzIM34nR0TNOoCA48gPGTANa6/C+wGV4nYQBXqp15yMukhEA
|
||||
AACAJ2iqIoXMYc0w3sXBQJ2BJyRYFBlZ0Czrz7xZEaBXrK5BcZjCARnmAp2Hfuvx
|
||||
i0lz0PHAz9f6hpjZuLEGLO7f3kGMcyEquYd89FHvP1yLxggYiXGKNDYSDZRK8Yy7
|
||||
MipqcnT4j5zDuFi744aO5fIchKp02z+ttGVt/i5zuGNh+do=
|
||||
Private-MAC: a9b12c6450e46fd7abbaaff5841f8a64f9597c7b2b59bd69d6fd3ceee0ca61ea
|
||||
`),
|
||||
},
|
||||
{
|
||||
desc: "invalid private key",
|
||||
priv: []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA3U4OOAi+F1Ct1n8HZIs1P39CWB0mKLvshouuklenZug27SuI
|
||||
14rjE+hOTNHYz/Pkvk5mmKuIdegMCe8FHAF6chygcEC9BDkowLO+2+f3sazGsu4A
|
||||
9H4pDuUkuIM9MwmZV7A4TJ19rRAgha+6JKKR5KeEosfiLvAtOu2Pjqz8ZrOrUUqQ
|
||||
1AJ71SkWMPTJFksTNmgaH7a0SgJ4vVYMlYIAeyoAgqn6Qvu5Kez5ROfeKD4zys/+
|
||||
iFenrgbJrC38GNe2rxtb8/gfy03023FlPAQjGd1VLjxm8jhcJFqgM+uHTGRckgjv
|
||||
d+VIkCbvTwpPWvvZxQcRtk073P9G8xpiNz2qbwIDAQABAoIBAQCFv37obqA0BxaI
|
||||
5AzbvyZXUdoO1s8RH0I7rn+7Ai6yCvXnMMBrRA0pIuTvmIOoaoZ8XXW0HzdByxQ7
|
||||
jLFR07Lk9Fgif328566xh/B5hyAzyW/tA9qf6P93eRVQTkDWb561WFMuOqCRz4VY
|
||||
RnQBYB88SeHnX1Zbd9xeGOUCHZoNlrilVpgjscGcFNxyDP72qvI79z1vV+R6dhaf
|
||||
YI2v1D6aqx9qM988ytOokNi79wYvSUxqitz3IOD5nBd9ZNBC0fDeVmHqqbHSvLrr
|
||||
LouF7PiUuVA2LaWfVCy5dVtLkS16qbsfqzUA4B8Eg/oF0vPpJ7QMVxKI5j2//ScL
|
||||
lQ9h6gUBAoGBAOQ0t9gGuHKOMcp3H9C2fzNVbbWTubJoUyzFGyx+U2aJ4byRbxS3
|
||||
5d9cVu1GpS2ZgW6izCmxTG61Q0qQd4iT8e5cnFRU1Q3aK29TTK5hptthknXwKkVN
|
||||
aUtlYKRM3TPYeTJ3WMQCY/Lzm2uVhT2ZGkpu0NaA5qiWllyPm7HlyQA/AoGBAPhC
|
||||
bzioaPlqzwNKtHCsDSyeXsxU1aJCuMCIcgOB1yzmaaeL95CwMouMgouFyQ/CtLtO
|
||||
cQEjymGzVynwC15s1vh1nCOWlQCx6Cjs9ko9bmecqziyyWg94gn82yLU7gClQH6v
|
||||
ezQ1n7/pb1DO/8dytO3+BZKSQH9lobzravGTcnRAoGAL8nKZfaiUXrtelSP2Qke;
|
||||
ggV1v/x7epzWLh3ontylYmelWfOqq1AHV0ri+TU+CdqHfD+jOWfjdZuHx+mQ3oz8
|
||||
sMm8Avzw0MHLLrjm6e2RH4fDP+dXMsQgy9Ui88UU3XKLjsHnWMSXYZ0aAuGA0XFq
|
||||
TAQAv6qmos9GFYQNOqe/+8kCgYEAv88H69eae5J9bTKr5R3Zc+7MmZy2Do70hbUm
|
||||
OfV4lbVUTmJDHWQ1OUKPnlL4fJfX4Zwquo23kPLqVnmjnwoCsabUw15Vs1rBX9Vt
|
||||
mQCLq7wNQlpIaKTfXw4hFXFkjdUf1oIKXGEiSK8mk+s9kKepDRlnsXklnUcbpRri
|
||||
xQQLF/ECgYAmKBSQtPuyA9d3dAZj96HhYZzDjD2EtAhSUyx31vgqr8C7mmShQXLh
|
||||
kFap4eAldBxySXp/5af7H1Xf4BIfbbc1prMM1vIRFTN6l6rbircak7bb9a/dgWmX
|
||||
iukFsFq0G0Y2zt9oHOB7pKV/Kff4o1WQ0hcCBD6pZGhbsVxXBi4Oaw==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`),
|
||||
pub: []byte(`ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDdTg44CL4XUK3WfwdkizU/f0JYHSYou+yGi66SV6dm6DbtK4jXiuMT6E5M0djP8+S+TmaYq4h16AwJ7wUcAXpyHKBwQL0EOSjAs77b5/exrMay7gD0fikO5SS4gz0zCZlXsDhMnX2tECCFr7okopHkp4Six+Iu8C067Y+OrPxms6tRSpDUAnvVKRYw9MkWSxM2aBoftrRKAni9VgyVggB7KgCCqfpC+7kp7PlE594oPjPKz/6IV6euBsmsLfwY17avG1vz+B/LTfTbcWU8BCMZ3VUuPGbyOFwkWqAz64dMZFySCO935UiQJu9PCk9a+9nFBxG2TTvc/0bzGmI3Papv`),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "invalid public key",
|
||||
priv: []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAve2um90K1SkpJD1vcjm2zUYUh5ZU7q1cmO7F0J/6MCEcq3vH
|
||||
fDPpPZ4uGLB9jPKzs6FYWhwFNW2oAsDvWSrwwxy5gl1dAdqp1wIm86gafShR0se5
|
||||
rSdhWKP40H2lHOysRC5Jr8cvVLgflvZ4PDMqr/63BKwwkT1vN2PuenYRAAIT77X9
|
||||
O0fumGQPKIxRGn5OPKEt1LzQ0+e/QlWrqZwzWDx5jqG3jbxibdcR/mHS60XdvusL
|
||||
UqxxWPjhVlDsKfvh2lt5sqsjulWW/GyNtlCfaTn2uu0nV8nbT2OvEO+oM/uyHos5
|
||||
7aIyePcOzCVM4dug6xJinqYTaVUsskKjPGUV6QIDAQABAoIBAQCBfis9k6DOIukt
|
||||
D0IL5DOxk2Vt6F5x+PsYPjva+SfwZrMQbC1fjlkpLM8LAFIpplRFVe1SSqZ2fhQ+
|
||||
BGNsLS3IKa6FprhCCl8f/BSoreWZjcLz7j63QxFJCUscg33u0aLGPbT5xtmLbpoD
|
||||
KHpjuRMSuZz475mRfQx1/IldL2B52sIAD6XRTgFoRG+mLu2iNVvuE0RVbASiyOUs
|
||||
lVwrGRI+5GuH8G6fDCJqpYzcm/S8VXmQc2jrbo/gQ76MkFxULqEMzadjN+XMXms7
|
||||
pGZLX6Hatubn1kmhl8l6+1GYLf1HVmWXoL+hgWwbfIn6WV9y/xpnoeoJfWcFLJli
|
||||
yABDx/mBAoGBAPhw3thyEP+5jdH2n1vz4X76yUbNJXaJGXozdoNfFKNOrYjFCLnD
|
||||
CzHJEQmDJoFCtF6TwgvFb90HNvtNLkbC81yotQ8rfDzNTlixUhycaSsCJBqw0loU
|
||||
wXoYQZiXpbfqT9Y7x7pwMxzRtkQYvyaowc7qF1xwJHhyCjDx38jAGnZxAoGBAMO1
|
||||
DXUpca09h+FujJkziyJStYq0YKqsuKXW7CuAq2iY70lzhv+SIPErqcYIWwi8JNv9
|
||||
EwBlEmSltFyGtxpeIVl6MJTil3vQ6eOSBCwt/E1YKvZoLv6mDf52Lc/wKtlecRPG
|
||||
Q7G2C1ioTD9lDiYysUDmkpfitiatFwEj+y606wL5AoGBAMlQJLM9Ets1D19QuWb4
|
||||
YwPS0aBGgZHgnD1yUBk5xW5jRajrCBwGmR6Zb+3GUUAyvhdZIccKEJAI1Zuiudnr
|
||||
BOpTZovJT92w+0hRP1khwPJxxLHAEGOgJ/r4hsbQMx+phVHylPBVFIXIxSm+5726
|
||||
x3kUJSPpVxQmTG3GwPBaAddxAoGALq+4QCTc22j8S0jl/X4QSOXWLPqOvOhrPBSj
|
||||
TlVpjpA9NRZ8M+eWODIkU/uWS+UmHdyndcamtp/ZAOGaOI4QApplkH7liEH0Kbeh
|
||||
izCFKaZIyXNdEp5mZDepAhvW/PfMnd0ENRaqakHrvovK7k3VfxgCDH2m2l8cR8df
|
||||
mmrKTXECgYEA300gTnT46pMU1Wr1Zq4vGauWzk3U4J9HUu3vNy+sg4EEZ9CoiNTw
|
||||
0a3f8u8gNQjB30koGW/5jYex3fUcnjTPqEGaiiGjI4oxMhquzqkVQ8FwnBAXJgT8
|
||||
nQVO8MZw8iFeSap0ILum8t60sp1/u9aCWJbjPtb/fhx0q7SLdjFEw8s=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`),
|
||||
pub: []byte(`AAAAB3NzaC1yc2EAAAADAQABAAABAQC9806b3QrVKSkkPW9yObbNRhSHllTurVyY7sXQn/owIRyre8d8M+k9ni4YsH2M8rOzoVhaHAU1bagCwO9ZKvDDHLmCXV0B2qnXAibzqBp9KFHSx7mtJ2FYo/jQfaUc7KxELkmvxy9UuB+W9ng8Myqv/rcErDCRPW83Y+56dhEAAhPvtf07R+6YZA8ojFEafk48oS3UvNDT579CVaupnDNYPHmOobeNvGJt1xH+YdLrRd2+6wtSrHFY+OFWUOwp++HaW3myqyO6VZb8bI22UJ9pOfa67SdXydtPY68Q76gz+7IeizntojJ49w7MJUzh26DrEmKephNpVSyyQqM8ZRXp`),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "private and public keys too short",
|
||||
priv: []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAve2um90K1SkpJD1vcjm2zUYUh5ZU7q1cmO7F0J/6MCEcq3vH
|
||||
fDPpPZ4uGLB9jPKzs6FYWhwFNW2oAsDvWSrwwxy5gl1dAdqp1wIm86gafShR0se5
|
||||
rSdhWKP40H2lHOysRC5Jr8cvVLgflvZ4PDMqr/63BKwwkT1vN2PuenYRAAIT77X9
|
||||
O0fumGQPKIxRGn5OPKEt1LzQ0+e/QlWrqZwzWDx5jqG3jbxibdcR/mHS60XdvusL
|
||||
UqxxWPjhVlDsKfvh2lt5sqsjulWW/GyNtlCfaTn2uu0nV8nbT2OvEO+oM/uyHos5
|
||||
7aIyePcOzCVM4dug6xJinqYTaVUsskKjPGUV6QIDAQABAoIBAQCBfis9k6DOIukt
|
||||
D0IL5DOxk2Vt6F5x+PsYPjva+SfwZrMQbC1fjlkpLM8LAFIpplRFVe1SSqZ2fhQ+
|
||||
BGNsLS3IKa6FprhCCl8f/BSoreWZjcLz7j63QxFJCUscg33u0aLGPbT5xtmLbpoD
|
||||
KHpjuRMSuZz475mRfQx1/IldL2B52sIAD6XRTgFoRG+mLu2iNVvuE0RVbASiyOUs
|
||||
lVwrGRI+5GuH8G6fDCJqpYzcm/S8VXmQc2jrbo/gQ76MkFxULqEMzadjN+XMXms7
|
||||
pGZLX6Hatubn1kmhl8l6+1GYLf1HVmWXoL+hgWwbfIn6WV9y/xpnoeoJfWcFLJli
|
||||
yABDx/mBAoGBAPhw3thyEP+5jdH2n1vz4X76yUbNJXaJGXozdoNfFKNOrYjFCLnD
|
||||
CzHJEQmDJoFCtF6TwgvFb90HNvtNLkbC81yotQ8rfDzNTlixUhycaSsCJBqw0loU
|
||||
wXoYQZiXpbfqT9Y7x7pwMxzRtkQYvyaowc7qF1xwJHhyCjDx38jAGnZxAoGBAMO1
|
||||
DXUpca09h+FujJkziyJStYq0YKqsuKXW7CuAq2iY70lzhv+SIPErqcYIWwi8JNv9
|
||||
EwBlEmSltFyGtxpeIVl6MJTil3vQ6eOSBCwt/E1YKvZoLv6mDf52Lc/wKtlecRPG
|
||||
Q7G2C1ioTD9lDiYysUDmkpfitiatFwEj+y606wL5AoGBAMlQJLM9Ets1D19QuWb4
|
||||
YwPS0aBGgZHgnD1yUBk5xW5jRajrCBwGmR6Zb+3GUUAyvhdZIccKEJAI1Zuiudnr
|
||||
BOpTZovJT92w+0hRP1khwPJxxLHAEGOgJ/r4hsbQMx+phVHylPBVFIXIxSm+5726
|
||||
x3kUJSPpVxQmTG3GwPBaAddxAoGALq+4QCTc22j8S0jl/X4QSOXWLPqOvOhrPBSj
|
||||
TlVpjpA9NRZ8M+eWODIkU/uWS+UmHdyndcamtp/ZAOGaOI4QApplkH7liEH0Kbeh
|
||||
izCFKaZIyXNdEp5mZDepAhvW/PfMnd0ENRaqakHrvovK7k3VfxgCDH2m2l8cR8df
|
||||
mmrKTXECgYEA300gTnT46pMU1Wr1Zq4vGauWzk3U4J9HUu3vNy+sg4EEZ9CoiNTw
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`),
|
||||
pub: []byte(`AAAAB3NzaC1yc2EAAAADAQABAAABAQC9806b3QrVKSkkPW9yObbNRhSHllTurVyY7sXQn/owIRyre8d8M+k9ni4YsH2M8rOzoVhaHAU1bagCwO9ZKvDDHLmCXV0B2qnXAibzqBp9KFHSx7mtJ2FYo/jQfaUc7KxELkmvxy9UuB+W9ng8Myqv/rcErDCRPW83Y+56dhEAAhPvtf07R+6YZA8ojFEafk48oS3UvNDT579CVaupnDNYPHmOobeNvGJt1xH+YdLrRd2+6wtSrHFY+OFWUOwp++HaW3myqyO6VZb8bI22UJ9pOfa67SdXydtPY68Q76gz+7IeizntojJ49w7MJUzh26DrEmKephNpVSyyQqM8`),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "private and public keys too long",
|
||||
priv: []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAz5J/f572H95c9DDZLrXT0kmjytznkvntSOjxmJM44fL8DQz2
|
||||
NINFi4awTNYD1eIIzaO4LLw+uXFWKD2P9LgtJ/Cxdb9LRi1OZ5Qrw/jj173zf/g+
|
||||
wpItjoakgAzerHxKAPj3DB8iHFfPq+3MfdY36SZHT0GOU7QIhnYULKWWuVfexx25
|
||||
VtgdGsmL9jwfAftzh00aCIej9zi2eSfGYfcIeRlSh9wvoYldrZbRvLTeMbW+YznW
|
||||
kH4W9taCGofrq/t8tN0beh9B7z2hMGxOLLnsxu3gQc2KIUqU5l1myL0rVncvSwZw
|
||||
ppQudZYtRyzmLOOm9PEvJHWvgu6KQBj5F24xrwIDAQABAoIBAQC0BgOMJMqjkxAd
|
||||
POxvhYUjoXhr7bDuGNKB5H38bNrto/aUPwSdQKilPPhUe1yyOCqYZwDJ06222aP2
|
||||
nIXooX+QX0EZtQHM6GhSjwByI78/kl/IQf30dCEMtpue7wqEn/ry4vooSiwkVsgm
|
||||
/cPX811kWS2JgHq2/7JRI8GVgzu4m/wLtOVUIUiSG/zNZWx/ThEvvE/528z5MZG5
|
||||
zGuQobHH+zfGYqk9IABcpNMH+4S353oPXAej2bCsQU6x+alM5z0fi+PuWIWtaDIb
|
||||
e/Va9WN2fghXF5lxu/+sCv8QkoPotbRfh0nLO0nTt4MUIFR0X/mVXbVWn+5SBhWC
|
||||
YUgcjychAoGBAOtLKKqkYzuOIyB2E3b7dPJ1XuzHOXj0Co5DoVNNs8TyEggoQPuj
|
||||
cTLUQaIN+M+MyNmtLi4GaF1dXRrJg7qZoJ681Vz0P+w+pso1UTQcja5G8iOwiKAD
|
||||
MIkyH9t9iW8yDN+J0dEzTqAgOPIDxkwDWuvwvsBleJ2EAV6qdecjLpIRAoGBAOHW
|
||||
0NGHYe4GCbt/gA5UVUYXehx9mckcLwyZJJThjTZXYr1kglRYa4de5YRMk9oPCHUu
|
||||
ODKqxL8CTcKyIijj1fJGDVcqTPFXlS4UZ31RLMvVnDaMID7V2zx+wxJ9onwhj798
|
||||
1k3fVahH2vXOFH9AogeHKDNyD1RdwDNOhBy95Me/AoGALV+bAf0dXbi1MWdTrZgk
|
||||
HzVfDs4EWTzGZFTKYWQUjKAZthT9IwmLpL+lwHhtSKjfeoqY4ys9KPP+JlJB4tQJ
|
||||
U1Ma2ggH46jZRRkvBZuT/s2TmCpMzn6O94YA+rSkshq2vMy491yrhtlv4cu0i6gB
|
||||
+om8XyGyNr3j/btlbSMtseECgYB66UL1Bk2SEc8yMI4tPlC6uQRIhUMxZRlmLeLu
|
||||
9GK6dIzUruMPrJ+5KTiY7GR7hTsBK4qCaNZzbnmLwQ8+WeGS3fVcvzTpFNWoIorA
|
||||
dXF/7l36ggD6scGEByl74syP6mQlv3eTIj2oPJM6vFIDf9WvayvB9A3LyMpWIiFc
|
||||
0yy0WQKBgQDCPCUvQhiOJyQ63n3pjFl5/YOtadl9KUD/CmdyUkCt69QoFgG0wTAV
|
||||
qalC9sysLQ1QI8A8GHNoNPjqMi7SWvzSgYN9TDRjS5GRlH13EALzP7AhWJWDoLYU
|
||||
9DXNAEQrPMtX4Lzre7FmrYqEYqwdcac+vyXVgDA7ti1LhDhj8mm3Sg12371237==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`),
|
||||
pub: []byte(`ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDPkn9/nvYf3lz0MNkutdPSSaPK3OeS+e1I6PGYkzjh8vwNDPY0g0WLhrBM1gPV4gjNo7gsvD65cVYoPY/0uC0n8LF1v0tGLU5nlCvD+OPXvfN/+D7Cki2OhqSADN6sfEoA+PcMHyIcV8+r7cx91jfpJkdPQY5TtAiGdhQspZa5V97HHblW2B0ayYv2PB8B+3OHTRoIh6P3OLZ5J8Zh9wh5GVKH3C+hiV2tltG8tN4xtb5jOdaQfhb21oIah+ur+3y03Rt6H0HvPaEwbE4suezG7eBBzYohSpTmXWbIvStWdy9LBnCmlC51li1HLOYs46b08S8kda+C7opAGPkXbjGvkj121`),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.wantErr {
|
||||
_, err := ppk.ConvertToPPK(tc.priv, tc.pub)
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
output, err := ppk.ConvertToPPK(tc.priv, tc.pub)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, output, tc.output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/gravitational/teleport/api/identityfile"
|
||||
apiutils "github.com/gravitational/teleport/api/utils"
|
||||
"github.com/gravitational/teleport/api/utils/sshutils"
|
||||
"github.com/gravitational/teleport/api/utils/sshutils/ppk"
|
||||
"github.com/gravitational/teleport/lib/auth"
|
||||
"github.com/gravitational/teleport/lib/auth/native"
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
@@ -72,6 +73,8 @@ type Key struct {
|
||||
Priv []byte `json:"Priv,omitempty"`
|
||||
// Pub is a public key
|
||||
Pub []byte `json:"Pub,omitempty"`
|
||||
// PPK is a PuTTY PPK-formatted keypair
|
||||
PPK []byte `json:"PPK,omitempty"`
|
||||
// Cert is an SSH client certificate
|
||||
Cert []byte `json:"Cert,omitempty"`
|
||||
// TLSCert is a PEM encoded client TLS x509 certificate.
|
||||
@@ -101,9 +104,15 @@ func NewKey() (key *Key, err error) {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
ppkFile, err := ppk.ConvertToPPK(priv, pub)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return &Key{
|
||||
Priv: priv,
|
||||
Pub: pub,
|
||||
PPK: ppkFile,
|
||||
KubeTLSCerts: make(map[string][]byte),
|
||||
DBTLSCerts: make(map[string][]byte),
|
||||
}, nil
|
||||
|
||||
@@ -24,11 +24,13 @@ import (
|
||||
osfs "io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/gravitational/teleport"
|
||||
"github.com/gravitational/teleport/api/constants"
|
||||
"github.com/gravitational/teleport/api/profile"
|
||||
"github.com/gravitational/teleport/api/utils/keypaths"
|
||||
"github.com/gravitational/teleport/lib/auth"
|
||||
@@ -140,6 +142,11 @@ func (fs *FSLocalKeyStore) AddKey(key *Key) error {
|
||||
if err := fs.writeBytes(key.TLSCert, fs.tlsCertPath(key.KeyIndex)); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if runtime.GOOS == constants.WindowsOS {
|
||||
if err := fs.writeBytes(key.PPK, fs.PPKFilePath(key.KeyIndex)); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Store per-cluster key data.
|
||||
if len(key.Cert) > 0 {
|
||||
@@ -197,6 +204,10 @@ func (fs *FSLocalKeyStore) DeleteKey(idx KeyIndex) error {
|
||||
fs.sshCAsPath(idx),
|
||||
fs.tlsCertPath(idx),
|
||||
}
|
||||
// we also need to delete the extra PuTTY-formatted .ppk file when running on Windows
|
||||
if runtime.GOOS == constants.WindowsOS {
|
||||
files = append(files, fs.PPKFilePath(idx))
|
||||
}
|
||||
for _, fn := range files {
|
||||
if err := os.Remove(fn); err != nil {
|
||||
return trace.ConvertSystemError(err)
|
||||
@@ -530,6 +541,11 @@ func (fs *fsLocalNonSessionKeyStore) sshCertPath(idx KeyIndex) string {
|
||||
return keypaths.SSHCertPath(fs.KeyDir, idx.ProxyHost, idx.Username, idx.ClusterName)
|
||||
}
|
||||
|
||||
// PPKFilePath returns the PPK (PuTTY-formatted) keypair path for the given KeyIndex.
|
||||
func (fs *fsLocalNonSessionKeyStore) PPKFilePath(idx KeyIndex) string {
|
||||
return keypaths.PPKFilePath(fs.KeyDir, idx.ProxyHost, idx.Username)
|
||||
}
|
||||
|
||||
// sshCAsPath returns the SSH CA certificates path for the given KeyIndex.
|
||||
func (fs *fsLocalNonSessionKeyStore) sshCAsPath(idx KeyIndex) string {
|
||||
return keypaths.SSHCAsPath(fs.KeyDir, idx.ProxyHost, idx.Username)
|
||||
|
||||
Reference in New Issue
Block a user