2024-08-04 14:34:41 -07:00
|
|
|
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
|
|
|
|
|
|
|
|
//PubkeyGroups []*openpgp.Entity
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewServer(publicKeys, privateKeys []string) (*Server, error) {
|
|
|
|
pub, err := loadKeysFromFiles(publicKeys)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
priv, err := loadKeysFromFiles(privateKeys)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Server{PublicKeys: pub, PrivateKeys: priv}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func 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()
|
|
|
|
|
|
|
|
keyring = append(keyring, keys...)
|
|
|
|
}
|
|
|
|
|
|
|
|
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, "Key not found", 500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err := key.Serialize(w)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Serialization error: %s\n", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) findPubKey(search string) *openpgp.Entity {
|
|
|
|
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 {
|
|
|
|
for _, k := range s.PrivateKeys {
|
2024-08-04 15:27:29 -07:00
|
|
|
fmt.Printf("%X\n", k.PrimaryKey.KeyId)
|
2024-08-04 14:34:41 -07:00
|
|
|
for _, id := range k.Identities {
|
|
|
|
if strings.ToLower(id.UserId.Name) == search {
|
|
|
|
return k
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.ToLower(id.UserId.Email) == search {
|
|
|
|
return k
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, sub := range k.Subkeys {
|
2024-08-04 15:27:29 -07:00
|
|
|
fmt.Printf("%#v\n", sub)
|
|
|
|
if sub.PrivateKey == nil {
|
|
|
|
continue
|
|
|
|
}
|
2024-08-04 14:34:41 -07:00
|
|
|
if fmt.Sprintf("%x", sub.PrivateKey.KeyId) == 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{
|
2024-08-04 15:27:29 -07:00
|
|
|
//"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",
|
2024-08-04 14:34:41 -07:00
|
|
|
},
|
|
|
|
[]string{
|
2024-08-04 15:27:29 -07:00
|
|
|
//"keys/gpg-generated/internal-private.asc",
|
|
|
|
"keys/private/Company.asc",
|
2024-08-04 14:34:41 -07:00
|
|
|
},
|
|
|
|
)
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|