diff options
author | FChannel0 <77419041+FChannel0@users.noreply.github.com> | 2021-07-03 16:17:46 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-03 16:17:46 -0700 |
commit | ab6edbbe8044d5a3c7d9456bd15e3a74af35111a (patch) | |
tree | b45a5860c9a8e89071324ab980316054e1030695 | |
parent | a3f45e6a5cb85a43364756bd28a14936d1d95ae7 (diff) | |
parent | d9cce000fdc8d804e73ff2fa4bfd2f1a151d90d9 (diff) |
Merge pull request #35 from the-sageman/pem-failsafe
In case the PEM key is missing, do not fail too hard.
-rw-r--r-- | database.go | 46 | ||||
-rw-r--r-- | main.go | 6 | ||||
-rw-r--r-- | verification.go | 103 |
3 files changed, 122 insertions, 33 deletions
diff --git a/database.go b/database.go index 6a871ba..baae16a 100644 --- a/database.go +++ b/database.go @@ -1,12 +1,15 @@ package main -import "fmt" -import "database/sql" -import _ "github.com/lib/pq" -import "time" -import "os" -import "strings" -import "sort" +import ( + "database/sql" + "fmt" + "os" + "sort" + "strings" + "time" + + _ "github.com/lib/pq" +) func GetActorFromDB(db *sql.DB, id string) Actor { var nActor Actor @@ -27,6 +30,10 @@ func GetActorFromDB(db *sql.DB, id string) Actor { } nActor.PublicKey = GetActorPemFromDB(db, publicKeyPem) + if nActor.PublicKey.PublicKeyPem == ""{ + err = CreatePublicKeyFromPrivate(db, &nActor, publicKeyPem) + CheckError(err, "error creating public key from private") + } return nActor } @@ -50,6 +57,10 @@ func GetActorByNameFromDB(db *sql.DB, name string) Actor { } nActor.PublicKey = GetActorPemFromDB(db, publicKeyPem) + if nActor.PublicKey.PublicKeyPem == ""{ + err = CreatePublicKeyFromPrivate(db, &nActor, publicKeyPem) + CheckError(err, "error creating public key from private") + } return nActor } @@ -1470,13 +1481,32 @@ func GetActorPemFromDB(db *sql.DB, pemID string) PublicKeyPem { defer rows.Close() rows.Next() rows.Scan(&pem.Id, &pem.Owner, &pem.PublicKeyPem) - f, _ := os.ReadFile(pem.PublicKeyPem) + f, err := os.ReadFile(pem.PublicKeyPem) + if err != nil{ + pem.PublicKeyPem = "" + return pem + } pem.PublicKeyPem = strings.ReplaceAll(string(f), "\r\n", `\n`) return pem } +func GetActorPemFileFromDB(db *sql.DB, pemID string) string{ + query := `select file from publickeypem where id=$1` + rows, err := db.Query(query, pemID) + + CheckError(err, "could not get public key filename from database") + + var file string + + defer rows.Close() + rows.Next() + rows.Scan(&file) + + return file +} + func MarkObjectSensitive(db *sql.DB, id string, sensitive bool) { var query = `update activitystream set sensitive=$1 where id=$2` _, err := db.Exec(query, sensitive, id) @@ -1899,7 +1899,8 @@ func MakeActivityRequestOutbox(db *sql.DB, activity Activity) { path = re.ReplaceAllString(path, "") sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date) - encSig := ActivitySign(db, *activity.Actor, sig) + encSig, err := ActivitySign(db, *activity.Actor, sig) + CheckError(err, "unable to sign activity response") signature := fmt.Sprintf("keyId=\"%s\",headers=\"(request-target) host date\",signature=\"%s\"", activity.Actor.PublicKey.Id, encSig) req.Header.Set("Content-Type", activitystreams) @@ -1937,7 +1938,8 @@ func MakeActivityRequest(db *sql.DB, activity Activity) { path = re.ReplaceAllString(path, "") sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date) - encSig := ActivitySign(db, *activity.Actor, sig) + encSig, err := ActivitySign(db, *activity.Actor, sig) + CheckError(err, "unable to sign activity response") signature := fmt.Sprintf("keyId=\"%s\",headers=\"(request-target) host date\",signature=\"%s\"", activity.Actor.PublicKey.Id, encSig) req.Header.Set("Content-Type", activitystreams) diff --git a/verification.go b/verification.go index c649a4e..1e9c50e 100644 --- a/verification.go +++ b/verification.go @@ -1,24 +1,30 @@ package main -import "fmt" -import "database/sql" -import _ "github.com/lib/pq" -import "net/smtp" -import "time" -import "os/exec" -import "os" -import "math/rand" -import "crypto" -import "crypto/rsa" -import "crypto/x509" -import "crypto/sha256" -import "encoding/pem" -import "encoding/base64" -import crand "crypto/rand" -import "io/ioutil" -import "strings" -import "net/http" -import "regexp" +import ( + "crypto" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "database/sql" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "math/rand" + "net/smtp" + "os" + "os/exec" + "time" + + _ "github.com/lib/pq" + + crand "crypto/rand" + "io/ioutil" + "net/http" + "regexp" + "strings" +) + type Verify struct { Type string @@ -527,6 +533,50 @@ func CreatePem(db *sql.DB, actor Actor) { } else { StorePemToDB(db, 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!`); +} + +func CreatePublicKeyFromPrivate(db *sql.DB, actor *Actor, publicKeyPem string) error{ + publicFilename := GetActorPemFileFromDB(db, publicKeyPem); + privateFilename := strings.ReplaceAll(publicFilename, "public.pem", "private.pem") + _, err := os.Stat(privateFilename) + if err == nil { + //Not a lost cause + priv, err := ioutil.ReadFile(privateFilename) + + 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) + CheckError(err, "failed to parse private key") + + publicKeyDer, err := x509.MarshalPKIXPublicKey(&key.PublicKey) + CheckError(err, "failed to marshal public key from private key") + pubKeyBlock := pem.Block{ + Type: "PUBLIC KEY", + Headers: nil, + Bytes: publicKeyDer, + } + publicFileWriter, err := os.Create(publicFilename) + CheckError(err, "error creating public pem file for " + actor.Name) + + err = pem.Encode(publicFileWriter, &pubKeyBlock) + CheckError(err, "error encoding public pem") + }else{ + fmt.Println(`Unable 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(db *sql.DB, actor Actor) { @@ -555,7 +605,7 @@ func StorePemToDB(db *sql.DB, actor Actor) { CheckError(err, "error creating publicKeyPem for actor ") } -func ActivitySign(db *sql.DB, actor Actor, signature string) string { +func ActivitySign(db *sql.DB, actor Actor, signature string) (string, error) { query := `select file from publicKeyPem where id=$1 ` rows, err := db.Query(query, actor.PublicKey.Id) @@ -581,10 +631,17 @@ func ActivitySign(db *sql.DB, actor Actor, signature string) string { hashed.Write([]byte(signature)) cipher, _ := rsa.SignPKCS1v15(rng, pub, crypto.SHA256, hashed.Sum(nil)) - return base64.StdEncoding.EncodeToString(cipher) + return base64.StdEncoding.EncodeToString(cipher), nil + }else{ + fmt.Println(`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") } - - return "" } func ActivityVerify(actor Actor, signature string, verify string) error { |