diff options
author | Niall Sheridan <nsheridan@gmail.com> | 2016-04-18 22:11:39 +0100 |
---|---|---|
committer | Niall Sheridan <nsheridan@gmail.com> | 2016-04-18 22:11:39 +0100 |
commit | 884013090b1b56b207f644393865c6057c9999ca (patch) | |
tree | 92d94820d0e131bc8385a7ca6540a96336b4e963 /server/signer |
Initial commit
Diffstat (limited to 'server/signer')
-rw-r--r-- | server/signer/signer.go | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/server/signer/signer.go b/server/signer/signer.go new file mode 100644 index 0000000..4ae5058 --- /dev/null +++ b/server/signer/signer.go @@ -0,0 +1,85 @@ +package signer + +import ( + "crypto/rand" + "fmt" + "io/ioutil" + "time" + + "github.com/nsheridan/cashier/lib" + "github.com/nsheridan/cashier/server/config" + "golang.org/x/crypto/ssh" +) + +type KeySigner struct { + ca ssh.Signer + validity time.Duration + principals []string + permissions map[string]string +} + +func (s *KeySigner) Sign(req *lib.SignRequest) (string, error) { + pubkey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(req.Key)) + if err != nil { + return "", err + } + expires := time.Now().Add(s.validity) + if req.ValidUntil.After(expires) { + req.ValidUntil = expires + } + cert := &ssh.Certificate{ + CertType: ssh.UserCert, + Key: pubkey, + KeyId: req.Principal, + ValidBefore: uint64(req.ValidUntil.Unix()), + ValidAfter: uint64(time.Now().Add(-5 * time.Minute).Unix()), + } + cert.ValidPrincipals = append(cert.ValidPrincipals, req.Principal) + cert.ValidPrincipals = append(cert.ValidPrincipals, s.principals...) + cert.Extensions = s.permissions + if err := cert.SignCert(rand.Reader, s.ca); err != nil { + return "", err + } + marshaled := ssh.MarshalAuthorizedKey(cert) + // Remove the trailing newline. + marshaled = marshaled[:len(marshaled)-1] + return string(marshaled), nil +} + +func makeperms(perms []string) map[string]string { + if len(perms) > 0 { + m := make(map[string]string) + for _, p := range perms { + m[p] = "" + } + return m + } + return map[string]string{ + "permit-X11-forwarding": "", + "permit-agent-forwarding": "", + "permit-port-forwarding": "", + "permit-pty": "", + "permit-user-rc": "", + } +} + +func NewSigner(conf config.SSH) (*KeySigner, error) { + data, err := ioutil.ReadFile(conf.SigningKey) + if err != nil { + return nil, fmt.Errorf("unable to read CA key %s: %v", conf.SigningKey, err) + } + key, err := ssh.ParsePrivateKey(data) + if err != nil { + return nil, fmt.Errorf("unable to parse CA key: %v", err) + } + validity, err := time.ParseDuration(conf.MaxAge) + if err != nil { + return nil, fmt.Errorf("error parsing duration '%s': %v", conf.MaxAge, err) + } + return &KeySigner{ + ca: key, + validity: validity, + principals: conf.Principals, + permissions: makeperms(conf.Permissions), + }, nil +} |