package main import ( "fmt" "os" "net/http" "syscall" "os/signal" "time" "context" //"encoding/json" "strings" "github.com/ProtonMail/go-crypto/openpgp" //"github.com/ProtonMail/go-crypto/openpgp/packet" ) type Server struct { PublicKeys openpgp.EntityList PrivateKeys openpgp.EntityList KeyMap map[string]*openpgp.Entity //PubkeyGroups []*openpgp.Entity } func NewServer(publicKeys, privateKeys []string) (*Server, error) { s := &Server{KeyMap: make(map[string]*openpgp.Entity)} pub, err := s.loadKeysFromFiles(publicKeys) if err != nil { return nil, err } s.PublicKeys = pub fmt.Println("Public keys:") for _, k := range pub { for name, _ := range k.Identities { fmt.Println("\t"+name) } fmt.Printf("\t%X\n", k.PrimaryKey.KeyId) if len(k.Subkeys) == 0 { continue } fmt.Println("\tSubkeys:") for _, sub := range k.Subkeys { str := []string{} if sub.PublicKey != nil { str = append(str, fmt.Sprintf("public: %X", sub.PublicKey.KeyId)) } if sub.PrivateKey != nil { str = append(str, fmt.Sprintf("private: %X", sub.PrivateKey.KeyId)) } fmt.Println("\t\t"+strings.Join(str, " / ")) } } priv, err := s.loadKeysFromFiles(privateKeys) if err != nil { return nil, err } s.PrivateKeys = priv fmt.Println("Private keys:") for _, k := range priv { for name, _ := range k.Identities { fmt.Println("\t"+name) } fmt.Printf("\t%X\n", k.PrimaryKey.KeyId) if len(k.Subkeys) == 0 { continue } fmt.Println("\tSubkeys:") for _, sub := range k.Subkeys { str := []string{} if sub.PublicKey != nil { str = append(str, fmt.Sprintf("public: %X", sub.PublicKey.KeyId)) } if sub.PrivateKey != nil { str = append(str, fmt.Sprintf("private: %X", sub.PrivateKey.KeyId)) } fmt.Println("\t\t"+strings.Join(str, " / ")) } } return s, nil } func (s *Server) loadKeysFromFiles(filenames []string) (openpgp.EntityList, error) { var keyring openpgp.EntityList for _, f := range filenames { file, err := os.Open(f) if err != nil { return nil, err } keys, err := openpgp.ReadArmoredKeyRing(file) if err != nil { file.Close() return nil, err } file.Close() for _, key := range keys { keyring = append(keyring, key) s.KeyMap[fmt.Sprintf("%x", key.PrimaryKey.KeyId)] = key for _, sub := range key.Subkeys { if sub.PublicKey != nil { s.KeyMap[fmt.Sprintf("%x", sub.PublicKey.KeyId)] = key } if sub.PrivateKey != nil { s.KeyMap[fmt.Sprintf("%x", sub.PrivateKey.KeyId)] = key } } } } return keyring, nil } func (s *Server) handler_publickey(w http.ResponseWriter, r *http.Request) { path := strings.Split(strings.Trim(r.URL.Path, "/"), "/") if len(path) < 2 { fmt.Fprintln(w, "missing path stuff") return } fmt.Println(r.URL.Path) search := strings.ToLower(path[1]) fmt.Println("searching for", search) key := s.findPubKey(search) if key == nil { http.Error(w, fmt.Sprintf("Key not found; searched for %q", search), 500) return } err := key.Serialize(w) if err != nil { fmt.Printf("Serialization error: %s\n", err) } } func (s *Server) findPubKey(search string) *openpgp.Entity { if k, found := s.KeyMap[search]; found { for _, sub := range k.Subkeys { if sub.PublicKey != nil && fmt.Sprintf("%x", sub.PublicKey.KeyId) == search { return k } } } for _, k := range s.PublicKeys { for _, id := range k.Identities { if strings.ToLower(id.UserId.Name) == search { return k } if strings.ToLower(id.UserId.Email) == search { return k } } } return nil } func (s *Server) handler_privatekey(w http.ResponseWriter, r *http.Request) { path := strings.Split(strings.Trim(r.URL.Path, "/"), "/") if len(path) < 2 { fmt.Fprintln(w, "missing path stuff") return } fmt.Println(r.URL.Path) search := strings.ToLower(path[1]) fmt.Println("searching for", search) key := s.findPrivKey(search) if key == nil { http.Error(w, "Key not found", 500) return } err := key.SerializePrivate(w, nil) if err != nil { fmt.Printf("Serialization error: %s\n", err) } } func (s *Server) findPrivKey(search string) *openpgp.Entity { if k, found := s.KeyMap[search]; found { if k.PrivateKey != nil && fmt.Sprintf("%x", k.PrivateKey.KeyId) == search { return k } for _, sub := range k.Subkeys { if sub.PrivateKey != nil && fmt.Sprintf("%x", sub.PrivateKey.KeyId) == search { return k } } } for _, k := range s.PrivateKeys { fmt.Printf("%X\n", k.PrimaryKey.KeyId) for _, id := range k.Identities { if strings.ToLower(id.UserId.Name) == search { return k } if strings.ToLower(id.UserId.Email) == search { return k } } } return nil } func (s *Server) handler_debug(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Public Keys:") for _, key := range s.PublicKeys { //fmt.Fprintf(w, "%#v\n", key.PrimaryIdentity()) fmt.Fprintf(w,"%s\n\t%X\n\t%X\n", key.PrimaryIdentity().Name, key.PrimaryKey.Fingerprint, key.PrimaryKey.KeyId, ) //j, err := json.Marshal(key) //if err != nil { // fmt.Fprintf(w, "ERROR: %s", err) // return //} //fmt.Fprintf(w,"\t\t%s\n", j) } fmt.Fprintln(w, "\nPrivate Keys:") for _, key := range s.PrivateKeys { //fmt.Fprintf(w, "%#v\n", key.PrimaryIdentity()) fmt.Fprintf(w,"%s\n\t%X\n\t%X\n", key.PrimaryIdentity().Name, key.PrimaryKey.Fingerprint, key.PrivateKey.KeyId, ) for _, sub := range key.Subkeys { fmt.Fprintf(w, "\t>%X\n\t>%X\n", sub.PublicKey.KeyId, sub.PrivateKey.KeyId, ) } } } func handler_default(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "henlo") } func run() error { sv, err := NewServer( []string{ //"keys/gpg-generated/cust-a.pub", //"keys/gpg-generated/cust-b.pub", //"keys/gpg-generated/internal-public.asc", "keys/public/Customer.asc", "keys/public/Company.asc", }, []string{ //"keys/gpg-generated/internal-private.asc", "keys/private/Company.asc", }, ) if err != nil { return err } mux := http.NewServeMux() mux.HandleFunc("/pubkey/", sv.handler_publickey) mux.HandleFunc("/privkey/", sv.handler_privatekey) mux.HandleFunc("/debug/", sv.handler_debug) mux.HandleFunc("/", handler_default) server := &http.Server{ Addr: ":8080", Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } done := make(chan os.Signal, 1) signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) go func() { fmt.Println("listening on", server.Addr) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { fmt.Println("Listen: ", err) } }() <-done fmt.Println("stopping") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { fmt.Println("Clean shutdown failed: ", err) } fmt.Println("goodbye") return nil } func main() { err := run() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }