func parseEd25519Key(req []byte) (*AddedKey, error) { var k ed25519KeyMsg if err := ssh.Unmarshal(req, &k); err != nil { return nil, err } priv := ed25519.PrivateKey(k.Priv) return &AddedKey{PrivateKey: &priv, Comment: k.Comments}, nil }
// Implemented based on the documentation at // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) { magic := append([]byte("openssh-key-v1"), 0) if !bytes.Equal(magic, key[0:len(magic)]) { return nil, errors.New("ssh: invalid openssh private key format") } remaining := key[len(magic):] var w struct { CipherName string KdfName string KdfOpts string NumKeys uint32 PubKey []byte PrivKeyBlock []byte } if err := Unmarshal(remaining, &w); err != nil { return nil, err } pk1 := struct { Check1 uint32 Check2 uint32 Keytype string Pub []byte Priv []byte Comment string Pad []byte `ssh:"rest"` }{} if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil { return nil, err } if pk1.Check1 != pk1.Check2 { return nil, errors.New("ssh: checkint mismatch") } // we only handle ed25519 keys currently if pk1.Keytype != KeyAlgoED25519 { return nil, errors.New("ssh: unhandled key type") } for i, b := range pk1.Pad { if int(b) != i+1 { return nil, errors.New("ssh: padding not as expected") } } if len(pk1.Priv) != ed25519.PrivateKeySize { return nil, errors.New("ssh: private key unexpected length") } pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize)) copy(pk, pk1.Priv) return &pk, nil }
func parseEd25519Cert(req []byte) (*AddedKey, error) { var k ed25519CertMsg if err := ssh.Unmarshal(req, &k); err != nil { return nil, err } pubKey, err := ssh.ParsePublicKey(k.CertBytes) if err != nil { return nil, err } priv := ed25519.PrivateKey(k.Priv) cert, ok := pubKey.(*ssh.Certificate) if !ok { return nil, errors.New("agent: bad ED25519 certificate") } return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil }