コミット
7fd2c4c487
|
@ -11,20 +11,23 @@ import (
|
|||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"golang.org/x/crypto/blake2s"
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"golang.org/x/crypto/blake2s"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
const (
|
||||
hmacPrefix = "hmac"
|
||||
rsaPrefix = "rsa"
|
||||
ecdsaPrefix = "ecdsa"
|
||||
ed25519Prefix = "ed25519"
|
||||
md4String = "md4"
|
||||
md5String = "md5"
|
||||
sha1String = "sha1"
|
||||
|
@ -214,6 +217,35 @@ func (r *rsaAlgorithm) String() string {
|
|||
return fmt.Sprintf("%s-%s", rsaPrefix, hashToDef[r.kind].name)
|
||||
}
|
||||
|
||||
var _ signer = &ed25519Algorithm{}
|
||||
|
||||
type ed25519Algorithm struct{}
|
||||
|
||||
func (r *ed25519Algorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) {
|
||||
ed25519K, ok := p.(ed25519.PrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("crypto.PrivateKey is not ed25519.PrivateKey")
|
||||
}
|
||||
return ed25519.Sign(ed25519K, sig), nil
|
||||
}
|
||||
|
||||
func (r *ed25519Algorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error {
|
||||
ed25519K, ok := pub.(ed25519.PublicKey)
|
||||
if !ok {
|
||||
return errors.New("crypto.PublicKey is not ed25519.PublicKey")
|
||||
}
|
||||
|
||||
if ed25519.Verify(ed25519K, toHash, signature) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("ed25519 verify failed")
|
||||
}
|
||||
|
||||
func (r *ed25519Algorithm) String() string {
|
||||
return fmt.Sprintf("%s", ed25519Prefix)
|
||||
}
|
||||
|
||||
var _ signer = &ecdsaAlgorithm{}
|
||||
|
||||
type ecdsaAlgorithm struct {
|
||||
|
@ -390,12 +422,16 @@ func newAlgorithm(algo string, key []byte) (hash.Hash, crypto.Hash, error) {
|
|||
func signerFromString(s string) (signer, error) {
|
||||
s = strings.ToLower(s)
|
||||
isEcdsa := false
|
||||
isEd25519 := false
|
||||
var algo string = ""
|
||||
if strings.HasPrefix(s, ecdsaPrefix) {
|
||||
algo = strings.TrimPrefix(s, ecdsaPrefix+"-")
|
||||
isEcdsa = true
|
||||
} else if strings.HasPrefix(s, rsaPrefix) {
|
||||
algo = strings.TrimPrefix(s, rsaPrefix+"-")
|
||||
} else if strings.HasPrefix(s, ed25519Prefix) {
|
||||
isEd25519 = true
|
||||
algo = "sha512"
|
||||
} else {
|
||||
return nil, fmt.Errorf("no signer matching %q", s)
|
||||
}
|
||||
|
@ -403,6 +439,9 @@ func signerFromString(s string) (signer, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isEd25519 {
|
||||
return &ed25519Algorithm{}, nil
|
||||
}
|
||||
if isEcdsa {
|
||||
return &ecdsaAlgorithm{
|
||||
Hash: hash,
|
||||
|
|
5
go.mod
5
go.mod
|
@ -1,8 +1,5 @@
|
|||
module github.com/go-fed/httpsig
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20180527072434-ab813273cd59
|
||||
golang.org/x/sys v0.0.0-20180525142821-c11f84a56e43 // indirect
|
||||
)
|
||||
require golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
|
||||
|
||||
go 1.13
|
||||
|
|
12
go.sum
12
go.sum
|
@ -1,4 +1,8 @@
|
|||
golang.org/x/crypto v0.0.0-20180527072434-ab813273cd59 h1:hk3yo72LXLapY9EXVttc3Z1rLOxT9IuAPPX3GpY2+jo=
|
||||
golang.org/x/crypto v0.0.0-20180527072434-ab813273cd59/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/sys v0.0.0-20180525142821-c11f84a56e43 h1:PvnWIWTbA7gsEBkKjt0HV9hckYfcqYv8s/ju7ArZ0do=
|
||||
golang.org/x/sys v0.0.0-20180525142821-c11f84a56e43/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
|
@ -52,6 +52,9 @@ const (
|
|||
ECDSA_SHA384 Algorithm = ecdsaPrefix + "-" + sha384String
|
||||
ECDSA_SHA512 Algorithm = ecdsaPrefix + "-" + sha512String
|
||||
ECDSA_RIPEMD160 Algorithm = ecdsaPrefix + "-" + ripemd160String
|
||||
// ED25519 algorithms
|
||||
// can only be SHA512
|
||||
ED25519 Algorithm = ed25519Prefix
|
||||
|
||||
// Just because you can glue things together, doesn't mean they will
|
||||
// work. The following options are not supported.
|
||||
|
|
226
httpsig_test.go
226
httpsig_test.go
|
@ -7,6 +7,7 @@ import (
|
|||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
|
@ -16,6 +17,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -43,12 +46,29 @@ type httpsigTest struct {
|
|||
expectedDigest string
|
||||
}
|
||||
|
||||
type ed25519PrivKey struct {
|
||||
Version int
|
||||
ObjectIdentifier struct {
|
||||
ObjectIdentifier asn1.ObjectIdentifier
|
||||
}
|
||||
PrivateKey []byte
|
||||
}
|
||||
|
||||
type ed25519PubKey struct {
|
||||
OBjectIdentifier struct {
|
||||
ObjectIdentifier asn1.ObjectIdentifier
|
||||
}
|
||||
PublicKey asn1.BitString
|
||||
}
|
||||
|
||||
var (
|
||||
privKey *rsa.PrivateKey
|
||||
macKey []byte
|
||||
tests []httpsigTest
|
||||
testSpecRSAPrivateKey *rsa.PrivateKey
|
||||
testSpecRSAPublicKey *rsa.PublicKey
|
||||
testEd25519PrivateKey ed25519.PrivateKey
|
||||
testEd25519PublicKey ed25519.PublicKey
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -57,6 +77,10 @@ func init() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pubEd25519Key, privEd25519Key, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
macKey = make([]byte, 128)
|
||||
err = readFullFromCrypto(macKey)
|
||||
if err != nil {
|
||||
|
@ -75,6 +99,18 @@ func init() {
|
|||
expectedAlgorithm: RSA_SHA512,
|
||||
expectedSignatureAlgorithm: "hs2019",
|
||||
},
|
||||
{
|
||||
name: "ed25519 signature",
|
||||
prefs: []Algorithm{ED25519},
|
||||
digestAlg: DigestSha512,
|
||||
headers: []string{"Date", "Digest"},
|
||||
scheme: Signature,
|
||||
privKey: privEd25519Key,
|
||||
pubKey: pubEd25519Key,
|
||||
pubKeyId: "pubKeyId",
|
||||
expectedAlgorithm: ED25519,
|
||||
expectedSignatureAlgorithm: "hs2019",
|
||||
},
|
||||
{
|
||||
name: "digest on rsa signature",
|
||||
prefs: []Algorithm{RSA_SHA512},
|
||||
|
@ -89,6 +125,20 @@ func init() {
|
|||
expectedSignatureAlgorithm: "hs2019",
|
||||
expectedDigest: "SHA-256=07PJQngqg8+BlomdI6zM7ieOxhINWI+iivJxBDSm3Dg=",
|
||||
},
|
||||
{
|
||||
name: "digest on ed25519 signature",
|
||||
prefs: []Algorithm{ED25519},
|
||||
digestAlg: DigestSha256,
|
||||
headers: []string{"Date", "Digest"},
|
||||
body: []byte("Last night as I lay dreaming This strangest kind of feeling Revealed its secret meaning And now I know..."),
|
||||
scheme: Signature,
|
||||
privKey: privEd25519Key,
|
||||
pubKey: pubEd25519Key,
|
||||
pubKeyId: "pubKeyId",
|
||||
expectedAlgorithm: ED25519,
|
||||
expectedSignatureAlgorithm: "hs2019",
|
||||
expectedDigest: "SHA-256=07PJQngqg8+BlomdI6zM7ieOxhINWI+iivJxBDSm3Dg=",
|
||||
},
|
||||
{
|
||||
name: "hmac signature",
|
||||
prefs: []Algorithm{HMAC_SHA256},
|
||||
|
@ -127,6 +177,18 @@ func init() {
|
|||
expectedAlgorithm: RSA_SHA512,
|
||||
expectedSignatureAlgorithm: "hs2019",
|
||||
},
|
||||
{
|
||||
name: "ed25519 authorization",
|
||||
prefs: []Algorithm{ED25519},
|
||||
digestAlg: DigestSha256,
|
||||
headers: []string{"Date", "Digest"},
|
||||
scheme: Authorization,
|
||||
privKey: privEd25519Key,
|
||||
pubKey: pubEd25519Key,
|
||||
pubKeyId: "pubKeyId",
|
||||
expectedAlgorithm: ED25519,
|
||||
expectedSignatureAlgorithm: "hs2019",
|
||||
},
|
||||
{
|
||||
name: "hmac authorization",
|
||||
prefs: []Algorithm{HMAC_SHA256},
|
||||
|
@ -198,6 +260,16 @@ func init() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
testEd25519PrivateKey, err = loadEd25519PrivateKey([]byte(testEd25519PrivateKeyPEM))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
testEd25519PublicKey, err = loadEd25519PublicKey([]byte(testEd25519PublicKeyPEM))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func toSignatureParameter(k, v string) string {
|
||||
|
@ -551,6 +623,69 @@ func Test_Signing_HTTP_Messages_AppendixC(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSigningEd25519(t *testing.T) {
|
||||
specTests := []struct {
|
||||
name string
|
||||
headers []string
|
||||
expectedSignature string
|
||||
}{
|
||||
{
|
||||
name: "Default Test",
|
||||
headers: []string{},
|
||||
// NOTE: In the Appendix C tests, the following is NOT included:
|
||||
// `headers="date"`
|
||||
// But httpsig will ALWAYS explicitly list the headers used in its
|
||||
// signature. Hence, I have introduced it here.
|
||||
//
|
||||
// NOTE: In verification, if there are no headers listed, the
|
||||
// default headers (date) are indeed used as required by the
|
||||
// specification.
|
||||
expectedSignature: `Authorization: Signature keyId="Test",algorithm="hs2019",headers="date",signature="6G9bNnUfph4pnl3j8l4UTcSPJVg6r4tM73eWFAn+w4IdIi8yzzZs65QlgM31lAuVCRKlqMzME9VGgMt16nU1AQ=="`,
|
||||
},
|
||||
{
|
||||
name: "Basic Test",
|
||||
headers: []string{"(request-target)", "host", "date"},
|
||||
expectedSignature: `Authorization: Signature keyId="Test",algorithm="hs2019",headers="(request-target) host date",signature="upsoNpw5oJTD3lTIQHEnDGWTaKmlT7o2c9Lz3kqy2UTwOEpEop3Sd7F/K2bYD2lQ4AH1HRyvC4/9AcKgNBg1AA=="`,
|
||||
},
|
||||
{
|
||||
name: "All Headers Test",
|
||||
headers: []string{"(request-target)", "host", "date", "content-type", "digest", "content-length"},
|
||||
expectedSignature: `Authorization: Signature keyId="Test",algorithm="hs2019",headers="(request-target) host date content-type digest content-length",signature="UkxhZl0W5/xcuCIP5xOPv4V6rX0TmaV2lmrYYGWauKhdFHihpW80tCqTNFDhyD+nYeGNCRSFRHmDS0bGm0PVAg=="`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range specTests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
test := test
|
||||
r, err := http.NewRequest("POST", "http://example.com/foo?param=value&pet=dog", bytes.NewBuffer([]byte(testSpecBody)))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating request: %s", err)
|
||||
}
|
||||
|
||||
r.Header["Date"] = []string{testSpecDate}
|
||||
r.Header["Host"] = []string{r.URL.Host}
|
||||
r.Header["Content-Length"] = []string{strconv.Itoa(len(testSpecBody))}
|
||||
r.Header["Content-Type"] = []string{"application/json"}
|
||||
setDigest(r)
|
||||
|
||||
s, _, err := NewSigner([]Algorithm{ED25519}, DigestSha256, test.headers, Authorization, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating signer: %s", err)
|
||||
}
|
||||
|
||||
if err := s.SignRequest(testEd25519PrivateKey, "Test", r, nil); err != nil {
|
||||
t.Fatalf("error signing request: %s", err)
|
||||
}
|
||||
|
||||
expectedAuth := test.expectedSignature
|
||||
gotAuth := fmt.Sprintf("Authorization: %s", r.Header["Authorization"][0])
|
||||
if gotAuth != expectedAuth {
|
||||
t.Errorf("Signature string mismatch\nGot: %s\nWant: %s", gotAuth, expectedAuth)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test_Verifying_HTTP_Messages_AppendixC implement tests from Appendix C
|
||||
// in the http signatures specification:
|
||||
// https://tools.ietf.org/html/draft-cavage-http-signatures-10#appendix-C
|
||||
|
@ -563,17 +698,17 @@ func Test_Verifying_HTTP_Messages_AppendixC(t *testing.T) {
|
|||
{
|
||||
name: "C.1. Default Test",
|
||||
headers: []string{},
|
||||
signature: `Signature keyId="Test",algorithm="hs2019",signature="SjWJWbWN7i0wzBvtPl8rbASWz5xQW6mcJmn+ibttBqtifLN7Sazz6m79cNfwwb8DMJ5cou1s7uEGKKCs+FLEEaDV5lp7q25WqS+lavg7T8hc0GppauB6hbgEKTwblDHYGEtbGmtdHgVCk9SuS13F0hZ8FD0k/5OxEPXe5WozsbM="`,
|
||||
signature: `Signature keyId="Test",algorithm="rsa-sha256",signature="SjWJWbWN7i0wzBvtPl8rbASWz5xQW6mcJmn+ibttBqtifLN7Sazz6m79cNfwwb8DMJ5cou1s7uEGKKCs+FLEEaDV5lp7q25WqS+lavg7T8hc0GppauB6hbgEKTwblDHYGEtbGmtdHgVCk9SuS13F0hZ8FD0k/5OxEPXe5WozsbM="`,
|
||||
},
|
||||
{
|
||||
name: "C.2. Basic Test",
|
||||
headers: []string{"(request-target)", "host", "date"},
|
||||
signature: `Signature keyId="Test",algorithm="hs2019",headers="(request-target) host date",signature="qdx+H7PHHDZgy4y/Ahn9Tny9V3GP6YgBPyUXMmoxWtLbHpUnXS2mg2+SbrQDMCJypxBLSPQR2aAjn7ndmw2iicw3HMbe8VfEdKFYRqzic+efkb3nndiv/x1xSHDJWeSWkx3ButlYSuBskLu6kd9Fswtemr3lgdDEmn04swr2Os0="`,
|
||||
signature: `Signature keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date",signature="qdx+H7PHHDZgy4y/Ahn9Tny9V3GP6YgBPyUXMmoxWtLbHpUnXS2mg2+SbrQDMCJypxBLSPQR2aAjn7ndmw2iicw3HMbe8VfEdKFYRqzic+efkb3nndiv/x1xSHDJWeSWkx3ButlYSuBskLu6kd9Fswtemr3lgdDEmn04swr2Os0="`,
|
||||
},
|
||||
{
|
||||
name: "C.3. All Headers Test",
|
||||
headers: []string{"(request-target)", "host", "date", "content-type", "digest", "content-length"},
|
||||
signature: `Signature keyId="Test",algorithm="hs2019",headers="(request-target) host date content-type digest content-length",signature="vSdrb+dS3EceC9bcwHSo4MlyKS59iFIrhgYkz8+oVLEEzmYZZvRs8rgOp+63LEM3v+MFHB32NfpB2bEKBIvB1q52LaEUHFv120V01IL+TAD48XaERZFukWgHoBTLMhYS2Gb51gWxpeIq8knRmPnYePbF5MOkR0Zkly4zKH7s1dE="`,
|
||||
signature: `Signature keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date content-type digest content-length",signature="vSdrb+dS3EceC9bcwHSo4MlyKS59iFIrhgYkz8+oVLEEzmYZZvRs8rgOp+63LEM3v+MFHB32NfpB2bEKBIvB1q52LaEUHFv120V01IL+TAD48XaERZFukWgHoBTLMhYS2Gb51gWxpeIq8knRmPnYePbF5MOkR0Zkly4zKH7s1dE="`,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -607,6 +742,59 @@ func Test_Verifying_HTTP_Messages_AppendixC(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestVerifyingEd25519(t *testing.T) {
|
||||
specTests := []struct {
|
||||
name string
|
||||
headers []string
|
||||
signature string
|
||||
}{
|
||||
{
|
||||
name: "Default Test",
|
||||
headers: []string{},
|
||||
signature: `Signature keyId="Test",algorithm="hs2019",headers="date",signature="6G9bNnUfph4pnl3j8l4UTcSPJVg6r4tM73eWFAn+w4IdIi8yzzZs65QlgM31lAuVCRKlqMzME9VGgMt16nU1AQ=="`,
|
||||
},
|
||||
{
|
||||
name: "Basic Test",
|
||||
headers: []string{"(request-target)", "host", "date"},
|
||||
signature: `Signature keyId="Test",algorithm="hs2019",headers="(request-target) host date",signature="upsoNpw5oJTD3lTIQHEnDGWTaKmlT7o2c9Lz3kqy2UTwOEpEop3Sd7F/K2bYD2lQ4AH1HRyvC4/9AcKgNBg1AA=="`,
|
||||
},
|
||||
{
|
||||
name: "All Headers Test",
|
||||
headers: []string{"(request-target)", "host", "date", "content-type", "digest", "content-length"},
|
||||
signature: `Signature keyId="Test",algorithm="hs2019",headers="(request-target) host date content-type digest content-length",signature="UkxhZl0W5/xcuCIP5xOPv4V6rX0TmaV2lmrYYGWauKhdFHihpW80tCqTNFDhyD+nYeGNCRSFRHmDS0bGm0PVAg=="`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range specTests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
test := test
|
||||
r, err := http.NewRequest("POST", "http://example.com/foo?param=value&pet=dog", bytes.NewBuffer([]byte(testSpecBody)))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating request: %s", err)
|
||||
}
|
||||
|
||||
r.Header["Date"] = []string{testSpecDate}
|
||||
r.Header["Host"] = []string{r.URL.Host}
|
||||
r.Header["Content-Length"] = []string{strconv.Itoa(len(testSpecBody))}
|
||||
r.Header["Content-Type"] = []string{"application/json"}
|
||||
setDigest(r)
|
||||
r.Header["Authorization"] = []string{test.signature}
|
||||
|
||||
v, err := NewVerifier(r)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating verifier: %s", err)
|
||||
}
|
||||
|
||||
if "Test" != v.KeyId() {
|
||||
t.Errorf("KeyId mismatch\nGot: %s\nWant: Test", v.KeyId())
|
||||
}
|
||||
if err := v.Verify(testEd25519PublicKey, ED25519); err != nil {
|
||||
t.Errorf("Verification failure: %s", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func loadPrivateKey(keyData []byte) (*rsa.PrivateKey, error) {
|
||||
pem, _ := pem.Decode(keyData)
|
||||
if pem.Type != "RSA PRIVATE KEY" {
|
||||
|
@ -616,6 +804,19 @@ func loadPrivateKey(keyData []byte) (*rsa.PrivateKey, error) {
|
|||
return x509.ParsePKCS1PrivateKey(pem.Bytes)
|
||||
}
|
||||
|
||||
// taken from https://blainsmith.com/articles/signing-jwts-with-gos-crypto-ed25519/
|
||||
func loadEd25519PrivateKey(keyData []byte) (ed25519.PrivateKey, error) {
|
||||
var block *pem.Block
|
||||
block, _ = pem.Decode(keyData)
|
||||
|
||||
var asn1PrivKey ed25519PrivKey
|
||||
asn1.Unmarshal(block.Bytes, &asn1PrivKey)
|
||||
|
||||
// [2:] is skipping the byte for TAG and the byte for LEN
|
||||
// see also https://tools.ietf.org/html/draft-ietf-curdle-pkix-10#section-10.3
|
||||
return ed25519.NewKeyFromSeed(asn1PrivKey.PrivateKey[2:]), nil
|
||||
}
|
||||
|
||||
func loadPublicKey(keyData []byte) (*rsa.PublicKey, error) {
|
||||
pem, _ := pem.Decode(keyData)
|
||||
if pem.Type != "PUBLIC KEY" {
|
||||
|
@ -630,6 +831,17 @@ func loadPublicKey(keyData []byte) (*rsa.PublicKey, error) {
|
|||
return key.(*rsa.PublicKey), nil
|
||||
}
|
||||
|
||||
// taken from https://blainsmith.com/articles/signing-jwts-with-gos-crypto-ed25519/
|
||||
func loadEd25519PublicKey(keyData []byte) (ed25519.PublicKey, error) {
|
||||
var block *pem.Block
|
||||
block, _ = pem.Decode(keyData)
|
||||
|
||||
var asn1PubKey ed25519PubKey
|
||||
asn1.Unmarshal(block.Bytes, &asn1PubKey)
|
||||
|
||||
return ed25519.PublicKey(asn1PubKey.PublicKey.Bytes), nil
|
||||
}
|
||||
|
||||
func setDigest(r *http.Request) ([]byte, error) {
|
||||
var bodyBytes []byte
|
||||
if _, ok := r.Header["Digest"]; !ok {
|
||||
|
@ -679,3 +891,11 @@ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCFENGw33yGihy92pDjZQhl0C3
|
|||
Z4UMR7EOcpfdUE9Hf3m/hs+FUR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJw
|
||||
oYi+1hqp1fIekaxsyQIDAQAB
|
||||
-----END PUBLIC KEY-----`
|
||||
|
||||
const testEd25519PrivateKeyPEM = `-----BEGIN PRIVATE KEY-----
|
||||
MC4CAQAwBQYDK2VwBCIEIAP+PK4NtdzCe04sbtwBvf9IShlky298SMMBqkCCToHn
|
||||
-----END PRIVATE KEY-----`
|
||||
|
||||
const testEd25519PublicKeyPEM = `-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEAhyP+7zpNCsr7/ipGJjK0zVszTEQ5tooyX3VLAnBSc1c=
|
||||
-----END PUBLIC KEY-----`
|
||||
|
|
読み込み中…
新しいイシューから参照