switch to common version of httpsig code
This commit is contained in:
parent
5a5080496c
commit
7e1bf702cc
|
@ -32,6 +32,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"humungus.tedunangst.com/r/webs/httpsig"
|
||||||
"humungus.tedunangst.com/r/webs/image"
|
"humungus.tedunangst.com/r/webs/image"
|
||||||
"humungus.tedunangst.com/r/webs/junk"
|
"humungus.tedunangst.com/r/webs/junk"
|
||||||
)
|
)
|
||||||
|
@ -69,7 +70,7 @@ func PostMsg(keyname string, key *rsa.PrivateKey, url string, msg []byte) error
|
||||||
}
|
}
|
||||||
req.Header.Set("User-Agent", "honksnonk/5.0; "+serverName)
|
req.Header.Set("User-Agent", "honksnonk/5.0; "+serverName)
|
||||||
req.Header.Set("Content-Type", theonetruename)
|
req.Header.Set("Content-Type", theonetruename)
|
||||||
zig(keyname, key, req, msg)
|
httpsig.SignRequest(keyname, key, req, msg)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
9
fun.go
9
fun.go
|
@ -29,6 +29,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"humungus.tedunangst.com/r/webs/htfilter"
|
"humungus.tedunangst.com/r/webs/htfilter"
|
||||||
|
"humungus.tedunangst.com/r/webs/httpsig"
|
||||||
)
|
)
|
||||||
|
|
||||||
func reverbolate(userid int64, honks []*Honk) {
|
func reverbolate(userid int64, honks []*Honk) {
|
||||||
|
@ -429,7 +430,7 @@ func ziggy(username string) (keyname string, key *rsa.PrivateKey) {
|
||||||
var data string
|
var data string
|
||||||
row.Scan(&data)
|
row.Scan(&data)
|
||||||
var err error
|
var err error
|
||||||
key, _, err = pez(data)
|
key, _, err = httpsig.DecodeKey(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error decoding %s seckey: %s", username, err)
|
log.Printf("error decoding %s seckey: %s", username, err)
|
||||||
return
|
return
|
||||||
|
@ -473,7 +474,7 @@ func zaggy(keyname string) (key *rsa.PublicKey) {
|
||||||
log.Printf("error finding %s pubkey owner", keyname)
|
log.Printf("error finding %s pubkey owner", keyname)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, key, err = pez(data)
|
_, key, err = httpsig.DecodeKey(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error decoding %s pubkey: %s", keyname, err)
|
log.Printf("error decoding %s pubkey: %s", keyname, err)
|
||||||
return
|
return
|
||||||
|
@ -483,7 +484,7 @@ func zaggy(keyname string) (key *rsa.PublicKey) {
|
||||||
log.Printf("error saving key: %s", err)
|
log.Printf("error saving key: %s", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, key, err = pez(data)
|
_, key, err = httpsig.DecodeKey(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error decoding %s pubkey: %s", keyname, err)
|
log.Printf("error decoding %s pubkey: %s", keyname, err)
|
||||||
return
|
return
|
||||||
|
@ -503,7 +504,7 @@ func makeitworksomehowwithoutregardforkeycontinuity(keyname string, r *http.Requ
|
||||||
ziggylock.Lock()
|
ziggylock.Lock()
|
||||||
delete(zaggies, keyname)
|
delete(zaggies, keyname)
|
||||||
ziggylock.Unlock()
|
ziggylock.Unlock()
|
||||||
return zag(r, payload)
|
return httpsig.VerifyRequest(r, payload, zaggy)
|
||||||
}
|
}
|
||||||
|
|
||||||
var thumbbiters map[int64]map[string]bool
|
var thumbbiters map[int64]map[string]bool
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -7,5 +7,5 @@ require (
|
||||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4
|
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
|
||||||
humungus.tedunangst.com/r/go-sqlite3 v1.1.3
|
humungus.tedunangst.com/r/go-sqlite3 v1.1.3
|
||||||
humungus.tedunangst.com/r/webs v0.5.6
|
humungus.tedunangst.com/r/webs v0.6.0
|
||||||
)
|
)
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -23,3 +23,5 @@ humungus.tedunangst.com/r/go-sqlite3 v1.1.3 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9
|
||||||
humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M=
|
humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M=
|
||||||
humungus.tedunangst.com/r/webs v0.5.6 h1:QY6VpWP+5Urys3bM8thtDjieoprhSUfHIMhvhiljhvY=
|
humungus.tedunangst.com/r/webs v0.5.6 h1:QY6VpWP+5Urys3bM8thtDjieoprhSUfHIMhvhiljhvY=
|
||||||
humungus.tedunangst.com/r/webs v0.5.6/go.mod h1:Ho+nmafD/aUWF7LnH+Yl2/b0ob7f2pCkXm4onteWvLE=
|
humungus.tedunangst.com/r/webs v0.5.6/go.mod h1:Ho+nmafD/aUWF7LnH+Yl2/b0ob7f2pCkXm4onteWvLE=
|
||||||
|
humungus.tedunangst.com/r/webs v0.6.0 h1:EAd08IqS8qwzPBqDUNRZbHPdbm0cs7FnXbCWeYHYFiY=
|
||||||
|
humungus.tedunangst.com/r/webs v0.6.0/go.mod h1:Ho+nmafD/aUWF7LnH+Yl2/b0ob7f2pCkXm4onteWvLE=
|
||||||
|
|
3
honk.go
3
honk.go
|
@ -34,6 +34,7 @@ import (
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"humungus.tedunangst.com/r/webs/htfilter"
|
"humungus.tedunangst.com/r/webs/htfilter"
|
||||||
|
"humungus.tedunangst.com/r/webs/httpsig"
|
||||||
"humungus.tedunangst.com/r/webs/image"
|
"humungus.tedunangst.com/r/webs/image"
|
||||||
"humungus.tedunangst.com/r/webs/junk"
|
"humungus.tedunangst.com/r/webs/junk"
|
||||||
"humungus.tedunangst.com/r/webs/login"
|
"humungus.tedunangst.com/r/webs/login"
|
||||||
|
@ -339,7 +340,7 @@ func inbox(w http.ResponseWriter, r *http.Request) {
|
||||||
if crappola(j) {
|
if crappola(j) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
keyname, err := zag(r, payload)
|
keyname, err := httpsig.VerifyRequest(r, payload, zaggy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("inbox message failed signature: %s", err)
|
log.Printf("inbox message failed signature: %s", err)
|
||||||
if keyname != "" {
|
if keyname != "" {
|
||||||
|
|
5
util.go
5
util.go
|
@ -48,6 +48,7 @@ import (
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
_ "humungus.tedunangst.com/r/go-sqlite3"
|
_ "humungus.tedunangst.com/r/go-sqlite3"
|
||||||
|
"humungus.tedunangst.com/r/webs/httpsig"
|
||||||
)
|
)
|
||||||
|
|
||||||
var savedstyleparams = make(map[string]string)
|
var savedstyleparams = make(map[string]string)
|
||||||
|
@ -223,11 +224,11 @@ func createuser(db *sql.DB, r *bufio.Reader) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pubkey, err := zem(&k.PublicKey)
|
pubkey, err := httpsig.EncodeKey(&k.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
seckey, err := zem(k)
|
seckey, err := httpsig.EncodeKey(k)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
207
zig.go
207
zig.go
|
@ -1,207 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func sb64(data []byte) string {
|
|
||||||
var sb strings.Builder
|
|
||||||
b64 := base64.NewEncoder(base64.StdEncoding, &sb)
|
|
||||||
b64.Write(data)
|
|
||||||
b64.Close()
|
|
||||||
return sb.String()
|
|
||||||
|
|
||||||
}
|
|
||||||
func b64s(s string) []byte {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
b64 := base64.NewDecoder(base64.StdEncoding, strings.NewReader(s))
|
|
||||||
io.Copy(&buf, b64)
|
|
||||||
return buf.Bytes()
|
|
||||||
}
|
|
||||||
func sb64sha256(content []byte) string {
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write(content)
|
|
||||||
return sb64(h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func zig(keyname string, key *rsa.PrivateKey, req *http.Request, content []byte) {
|
|
||||||
headers := []string{"(request-target)", "date", "host", "content-type", "digest"}
|
|
||||||
var stuff []string
|
|
||||||
for _, h := range headers {
|
|
||||||
var s string
|
|
||||||
switch h {
|
|
||||||
case "(request-target)":
|
|
||||||
s = strings.ToLower(req.Method) + " " + req.URL.RequestURI()
|
|
||||||
case "date":
|
|
||||||
s = req.Header.Get(h)
|
|
||||||
if s == "" {
|
|
||||||
s = time.Now().UTC().Format(http.TimeFormat)
|
|
||||||
req.Header.Set(h, s)
|
|
||||||
}
|
|
||||||
case "host":
|
|
||||||
s = req.Header.Get(h)
|
|
||||||
if s == "" {
|
|
||||||
s = req.URL.Hostname()
|
|
||||||
req.Header.Set(h, s)
|
|
||||||
}
|
|
||||||
case "content-type":
|
|
||||||
s = req.Header.Get(h)
|
|
||||||
case "digest":
|
|
||||||
s = req.Header.Get(h)
|
|
||||||
if s == "" {
|
|
||||||
s = "SHA-256=" + sb64sha256(content)
|
|
||||||
req.Header.Set(h, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stuff = append(stuff, h+": "+s)
|
|
||||||
}
|
|
||||||
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write([]byte(strings.Join(stuff, "\n")))
|
|
||||||
sig, _ := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
|
|
||||||
bsig := sb64(sig)
|
|
||||||
|
|
||||||
sighdr := fmt.Sprintf(`keyId="%s",algorithm="%s",headers="%s",signature="%s"`,
|
|
||||||
keyname, "rsa-sha256", strings.Join(headers, " "), bsig)
|
|
||||||
req.Header.Set("Signature", sighdr)
|
|
||||||
}
|
|
||||||
|
|
||||||
var re_sighdrval = regexp.MustCompile(`(.*)="(.*)"`)
|
|
||||||
|
|
||||||
func zag(req *http.Request, content []byte) (string, error) {
|
|
||||||
sighdr := req.Header.Get("Signature")
|
|
||||||
|
|
||||||
var keyname, algo, heads, bsig string
|
|
||||||
for _, v := range strings.Split(sighdr, ",") {
|
|
||||||
m := re_sighdrval.FindStringSubmatch(v)
|
|
||||||
if len(m) != 3 {
|
|
||||||
return "", fmt.Errorf("bad scan: %s from %s\n", v, sighdr)
|
|
||||||
}
|
|
||||||
switch m[1] {
|
|
||||||
case "keyId":
|
|
||||||
keyname = m[2]
|
|
||||||
case "algorithm":
|
|
||||||
algo = m[2]
|
|
||||||
case "headers":
|
|
||||||
heads = m[2]
|
|
||||||
case "signature":
|
|
||||||
bsig = m[2]
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("bad sig val: %s", m[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if keyname == "" || algo == "" || heads == "" || bsig == "" {
|
|
||||||
return "", fmt.Errorf("missing a sig value")
|
|
||||||
}
|
|
||||||
|
|
||||||
key := zaggy(keyname)
|
|
||||||
if key == nil {
|
|
||||||
return keyname, fmt.Errorf("no key for %s", keyname)
|
|
||||||
}
|
|
||||||
headers := strings.Split(heads, " ")
|
|
||||||
var stuff []string
|
|
||||||
for _, h := range headers {
|
|
||||||
var s string
|
|
||||||
switch h {
|
|
||||||
case "(request-target)":
|
|
||||||
s = strings.ToLower(req.Method) + " " + req.URL.RequestURI()
|
|
||||||
case "host":
|
|
||||||
s = req.Host
|
|
||||||
if s != serverName {
|
|
||||||
log.Printf("caution: servername host header mismatch")
|
|
||||||
}
|
|
||||||
case "digest":
|
|
||||||
s = req.Header.Get(h)
|
|
||||||
expv := "SHA-256=" + sb64sha256(content)
|
|
||||||
if s != expv {
|
|
||||||
return "", fmt.Errorf("digest header '%s' did not match content", s)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
s = req.Header.Get(h)
|
|
||||||
}
|
|
||||||
stuff = append(stuff, h+": "+s)
|
|
||||||
}
|
|
||||||
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write([]byte(strings.Join(stuff, "\n")))
|
|
||||||
sig := b64s(bsig)
|
|
||||||
err := rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), sig)
|
|
||||||
if err != nil {
|
|
||||||
return keyname, err
|
|
||||||
}
|
|
||||||
return keyname, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func pez(s string) (pri *rsa.PrivateKey, pub *rsa.PublicKey, err error) {
|
|
||||||
block, _ := pem.Decode([]byte(s))
|
|
||||||
if block == nil {
|
|
||||||
err = fmt.Errorf("no pem data")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch block.Type {
|
|
||||||
case "PUBLIC KEY":
|
|
||||||
var k interface{}
|
|
||||||
k, err = x509.ParsePKIXPublicKey(block.Bytes)
|
|
||||||
if k != nil {
|
|
||||||
pub, _ = k.(*rsa.PublicKey)
|
|
||||||
}
|
|
||||||
case "RSA PUBLIC KEY":
|
|
||||||
pub, err = x509.ParsePKCS1PublicKey(block.Bytes)
|
|
||||||
case "RSA PRIVATE KEY":
|
|
||||||
pri, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
||||||
if err == nil {
|
|
||||||
pub = &pri.PublicKey
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("unknown key type")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func zem(i interface{}) (string, error) {
|
|
||||||
var b pem.Block
|
|
||||||
var err error
|
|
||||||
switch k := i.(type) {
|
|
||||||
case *rsa.PrivateKey:
|
|
||||||
b.Type = "RSA PRIVATE KEY"
|
|
||||||
b.Bytes = x509.MarshalPKCS1PrivateKey(k)
|
|
||||||
case *rsa.PublicKey:
|
|
||||||
b.Type = "PUBLIC KEY"
|
|
||||||
b.Bytes, err = x509.MarshalPKIXPublicKey(k)
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("unknown key type: %s", k)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(pem.EncodeToMemory(&b)), nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue