From 1892327cee2c3fa1d3bea729bd08eb63c2189a96 Mon Sep 17 00:00:00 2001 From: FChannel <> Date: Sat, 30 Apr 2022 11:00:55 -0700 Subject: restructured code base to prevent circular dependicies --- db/pem.go | 310 +++++--------------------------------------------------------- 1 file changed, 22 insertions(+), 288 deletions(-) (limited to 'db/pem.go') diff --git a/db/pem.go b/db/pem.go index dedb137..66bf25a 100644 --- a/db/pem.go +++ b/db/pem.go @@ -2,270 +2,21 @@ package db import ( "crypto" - crand "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/pem" - "errors" - "fmt" - "io/ioutil" - "net/http" - "os" - "regexp" "strings" "time" "github.com/FChannel0/FChannel-Server/activitypub" "github.com/FChannel0/FChannel-Server/webfinger" + "github.com/gofiber/fiber/v2" ) -func GetActorPemFromDB(pemID string) (activitypub.PublicKeyPem, error) { - var pem activitypub.PublicKeyPem - - query := `select id, owner, file from publickeypem where id=$1` - - rows, err := db.Query(query, pemID) - if err != nil { - return pem, err - } - - defer rows.Close() - - rows.Next() - rows.Scan(&pem.Id, &pem.Owner, &pem.PublicKeyPem) - f, err := os.ReadFile(pem.PublicKeyPem) - if err != nil { - return pem, err - } - - pem.PublicKeyPem = strings.ReplaceAll(string(f), "\r\n", `\n`) - - return pem, nil -} - -func GetActorPemFileFromDB(pemID string) (string, error) { - query := `select file from publickeypem where id=$1` - rows, err := db.Query(query, pemID) - if err != nil { - return "", err - } - - defer rows.Close() - - var file string - rows.Next() - rows.Scan(&file) - - return file, nil -} - -func CreatePem(actor activitypub.Actor) error { - privatekey, err := rsa.GenerateKey(crand.Reader, 2048) - if err != nil { - return err - } - - privateKeyBytes := x509.MarshalPKCS1PrivateKey(privatekey) - - privateKeyBlock := &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: privateKeyBytes, - } - - privatePem, err := os.Create("./pem/board/" + actor.Name + "-private.pem") - if err != nil { - return err - } - - if err := pem.Encode(privatePem, privateKeyBlock); err != nil { - return err - } - - publickey := &privatekey.PublicKey - publicKeyBytes, err := x509.MarshalPKIXPublicKey(publickey) - if err != nil { - return err - } - - publicKeyBlock := &pem.Block{ - Type: "PUBLIC KEY", - Bytes: publicKeyBytes, - } - - publicPem, err := os.Create("./pem/board/" + actor.Name + "-public.pem") - if err != nil { - return err - } - - if err := pem.Encode(publicPem, publicKeyBlock); err != nil { - return err - } - - _, err = os.Stat("./pem/board/" + actor.Name + "-public.pem") - if os.IsNotExist(err) { - return err - } else { - return StorePemToDB(actor) - } - - fmt.Println(`Created PEM keypair for the "` + actor.Name + `" board. Please keep in mind that -the PEM key is crucial in identifying yourself as the legitimate owner of the board, -so DO NOT LOSE IT!!! If you lose it, YOU WILL LOSE ACCESS TO YOUR BOARD!`) - - return nil -} - -func CreatePublicKeyFromPrivate(actor *activitypub.Actor, publicKeyPem string) error { - publicFilename, err := GetActorPemFileFromDB(publicKeyPem) - if err != nil { - return err - } - - privateFilename := strings.ReplaceAll(publicFilename, "public.pem", "private.pem") - if _, err := os.Stat(privateFilename); err == nil { - // Not a lost cause - priv, err := ioutil.ReadFile(privateFilename) - if err != nil { - return err - } - - block, _ := pem.Decode([]byte(priv)) - if block == nil || block.Type != "RSA PRIVATE KEY" { - return errors.New("failed to decode PEM block containing public key") - } - - key, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return err - } - - publicKeyDer, err := x509.MarshalPKIXPublicKey(&key.PublicKey) - if err != nil { - return err - } - - pubKeyBlock := pem.Block{ - Type: "PUBLIC KEY", - Headers: nil, - Bytes: publicKeyDer, - } - - publicFileWriter, err := os.Create(publicFilename) - if err != nil { - return err - } - - if err := pem.Encode(publicFileWriter, &pubKeyBlock); err != nil { - return err - } - } else { - fmt.Println(`\nUnable to locate private key from public key generation. Now, -this means that you are now missing the proof that you are the -owner of the "` + actor.Name + `" board. If you are the developer, -then your job is just as easy as generating a new keypair, but -if this board is live, then you'll also have to convince the other -owners to switch their public keys for you so that they will start -accepting your posts from your board from this site. Good luck ;)`) - return errors.New("unable to locate private key") - } - return nil -} - -func StorePemToDB(actor activitypub.Actor) error { - query := "select publicKeyPem from actor where id=$1" - rows, err := db.Query(query, actor.Id) - if err != nil { - return err - } - - defer rows.Close() - - var result string - rows.Next() - rows.Scan(&result) - - if result != "" { - return errors.New("already storing public key for actor") - } - - publicKeyPem := actor.Id + "#main-key" - query = "update actor set publicKeyPem=$1 where id=$2" - if _, err := db.Exec(query, publicKeyPem, actor.Id); err != nil { - return err - } - - file := "./pem/board/" + actor.Name + "-public.pem" - query = "insert into publicKeyPem (id, owner, file) values($1, $2, $3)" - _, err = db.Exec(query, publicKeyPem, actor.Id, file) - return err -} -func ActivitySign(actor activitypub.Actor, signature string) (string, error) { - query := `select file from publicKeyPem where id=$1 ` - - rows, err := db.Query(query, actor.PublicKey.Id) - if err != nil { - return "", err - } - - defer rows.Close() - - var file string - rows.Next() - rows.Scan(&file) - - file = strings.ReplaceAll(file, "public.pem", "private.pem") - _, err = os.Stat(file) - if err != nil { - fmt.Println(`\n Unable to locate private key. Now, -this means that you are now missing the proof that you are the -owner of the "` + actor.Name + `" board. If you are the developer, -then your job is just as easy as generating a new keypair, but -if this board is live, then you'll also have to convince the other -owners to switch their public keys for you so that they will start -accepting your posts from your board from this site. Good luck ;)`) - return "", errors.New("unable to locate private key") - } - - publickey, err := ioutil.ReadFile(file) - if err != nil { - return "", err - } - - block, _ := pem.Decode(publickey) - - pub, _ := x509.ParsePKCS1PrivateKey(block.Bytes) - rng := crand.Reader - hashed := sha256.New() - hashed.Write([]byte(signature)) - cipher, _ := rsa.SignPKCS1v15(rng, pub, crypto.SHA256, hashed.Sum(nil)) - - return base64.StdEncoding.EncodeToString(cipher), nil -} - -func ActivityVerify(actor activitypub.Actor, signature string, verify string) error { - sig, _ := base64.StdEncoding.DecodeString(signature) - - if actor.PublicKey.PublicKeyPem == "" { - _actor, err := webfinger.FingerActor(actor.Id) - if err != nil { - return err - } - actor = _actor - } - - block, _ := pem.Decode([]byte(actor.PublicKey.PublicKeyPem)) - pub, _ := x509.ParsePKIXPublicKey(block.Bytes) - - hashed := sha256.New() - hashed.Write([]byte(verify)) - - return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hashed.Sum(nil), sig) -} - -func VerifyHeaderSignature(r *http.Request, actor activitypub.Actor) bool { - s := ParseHeaderSignature(r.Header.Get("Signature")) +func VerifyHeaderSignature(ctx *fiber.Ctx, actor activitypub.Actor) bool { + s := activitypub.ParseHeaderSignature(ctx.Get("Signature")) var method string var path string @@ -283,24 +34,24 @@ func VerifyHeaderSignature(r *http.Request, actor activitypub.Actor) bool { switch e { case "(request-target)": - method = strings.ToLower(r.Method) - path = r.URL.Path + method = strings.ToLower(ctx.Method()) + path = ctx.Path() sig += "(request-target): " + method + " " + path + "" + nl break case "host": - host = r.Host + host = ctx.Hostname() sig += "host: " + host + "" + nl break case "date": - date = r.Header.Get("date") + date = ctx.Get("date") sig += "date: " + date + "" + nl break case "digest": - digest = r.Header.Get("digest") + digest = ctx.Get("digest") sig += "digest: " + digest + "" + nl break case "content-length": - contentLength = r.Header.Get("content-length") + contentLength = ctx.Get("content-length") sig += "content-length: " + contentLength + "" + nl break } @@ -323,39 +74,22 @@ func VerifyHeaderSignature(r *http.Request, actor activitypub.Actor) bool { return true } -func ParseHeaderSignature(signature string) Signature { - var nsig Signature - - keyId := regexp.MustCompile(`keyId=`) - headers := regexp.MustCompile(`headers=`) - sig := regexp.MustCompile(`signature=`) - algo := regexp.MustCompile(`algorithm=`) - - signature = strings.ReplaceAll(signature, "\"", "") - parts := strings.Split(signature, ",") - - for _, e := range parts { - if keyId.MatchString(e) { - nsig.KeyId = keyId.ReplaceAllString(e, "") - continue - } +func ActivityVerify(actor activitypub.Actor, signature string, verify string) error { + sig, _ := base64.StdEncoding.DecodeString(signature) - if headers.MatchString(e) { - header := headers.ReplaceAllString(e, "") - nsig.Headers = strings.Split(header, " ") - continue + if actor.PublicKey.PublicKeyPem == "" { + _actor, err := webfinger.FingerActor(actor.Id) + if err != nil { + return err } + actor = _actor + } - if sig.MatchString(e) { - nsig.Signature = sig.ReplaceAllString(e, "") - continue - } + block, _ := pem.Decode([]byte(actor.PublicKey.PublicKeyPem)) + pub, _ := x509.ParsePKIXPublicKey(block.Bytes) - if algo.MatchString(e) { - nsig.Algorithm = algo.ReplaceAllString(e, "") - continue - } - } + hashed := sha256.New() + hashed.Write([]byte(verify)) - return nsig + return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hashed.Sum(nil), sig) } -- cgit v1.2.3