2020-08-01 23:59:20 +00:00
|
|
|
package xkeypairs
|
2020-07-25 09:13:19 +00:00
|
|
|
|
|
|
|
import (
|
2020-08-02 09:39:56 +00:00
|
|
|
"crypto"
|
2020-07-25 09:13:19 +00:00
|
|
|
"crypto/ecdsa"
|
|
|
|
"crypto/rsa"
|
2020-08-01 07:32:17 +00:00
|
|
|
"crypto/x509"
|
2020-07-25 09:13:19 +00:00
|
|
|
"encoding/base64"
|
2020-08-01 07:32:17 +00:00
|
|
|
"encoding/pem"
|
2020-07-25 09:13:19 +00:00
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"math/big"
|
2020-08-01 07:32:17 +00:00
|
|
|
mathrand "math/rand"
|
2020-07-25 09:13:19 +00:00
|
|
|
|
|
|
|
"git.rootprojects.org/root/keypairs"
|
|
|
|
)
|
|
|
|
|
2020-08-02 09:39:56 +00:00
|
|
|
// MarshalPEMPublicKey outputs the given public key as JWK
|
|
|
|
func MarshalPEMPublicKey(pubkey crypto.PublicKey) ([]byte, error) {
|
|
|
|
block, err := marshalDERPublicKey(pubkey)
|
|
|
|
if nil != err {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return pem.EncodeToMemory(block), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalDERPublicKey outputs the given public key as JWK
|
|
|
|
func MarshalDERPublicKey(pubkey crypto.PublicKey) ([]byte, error) {
|
|
|
|
block, err := marshalDERPublicKey(pubkey)
|
|
|
|
if nil != err {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return block.Bytes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// marshalDERPublicKey outputs the given public key as JWK
|
|
|
|
func marshalDERPublicKey(pubkey crypto.PublicKey) (*pem.Block, error) {
|
|
|
|
|
|
|
|
var der []byte
|
|
|
|
var typ string
|
|
|
|
var err error
|
|
|
|
switch k := pubkey.(type) {
|
|
|
|
case *rsa.PublicKey:
|
|
|
|
der = x509.MarshalPKCS1PublicKey(k)
|
|
|
|
typ = "RSA PUBLIC KEY"
|
|
|
|
case *ecdsa.PublicKey:
|
|
|
|
typ = "PUBLIC KEY"
|
|
|
|
der, err = x509.MarshalPKIXPublicKey(k)
|
|
|
|
if nil != err {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
panic("Developer Error: impossible key type")
|
|
|
|
}
|
|
|
|
|
|
|
|
return &pem.Block{
|
|
|
|
Bytes: der,
|
|
|
|
Type: typ,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-07-25 09:13:19 +00:00
|
|
|
// MarshalJWKPrivateKey outputs the given private key as JWK
|
|
|
|
func MarshalJWKPrivateKey(privkey keypairs.PrivateKey) []byte {
|
|
|
|
// thumbprint keys are alphabetically sorted and only include the necessary public parts
|
|
|
|
switch k := privkey.(type) {
|
|
|
|
case *rsa.PrivateKey:
|
|
|
|
return MarshalRSAPrivateKey(k)
|
|
|
|
case *ecdsa.PrivateKey:
|
|
|
|
return MarshalECPrivateKey(k)
|
|
|
|
default:
|
|
|
|
// this is unreachable because we know the types that we pass in
|
|
|
|
log.Printf("keytype: %t, %+v\n", privkey, privkey)
|
|
|
|
panic(keypairs.ErrInvalidPublicKey)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-01 07:32:17 +00:00
|
|
|
// MarshalDERPrivateKey outputs the given private key as ASN.1 DER
|
|
|
|
func MarshalDERPrivateKey(privkey keypairs.PrivateKey) ([]byte, error) {
|
|
|
|
// thumbprint keys are alphabetically sorted and only include the necessary public parts
|
|
|
|
switch k := privkey.(type) {
|
|
|
|
case *rsa.PrivateKey:
|
|
|
|
return x509.MarshalPKCS1PrivateKey(k), nil
|
|
|
|
case *ecdsa.PrivateKey:
|
|
|
|
return x509.MarshalECPrivateKey(k)
|
|
|
|
default:
|
|
|
|
// this is unreachable because we know the types that we pass in
|
|
|
|
log.Printf("keytype: %t, %+v\n", privkey, privkey)
|
|
|
|
panic(keypairs.ErrInvalidPublicKey)
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func marshalDERPrivateKey(privkey keypairs.PrivateKey) (*pem.Block, error) {
|
|
|
|
var typ string
|
|
|
|
var bytes []byte
|
|
|
|
var err error
|
|
|
|
|
|
|
|
switch k := privkey.(type) {
|
|
|
|
case *rsa.PrivateKey:
|
2020-08-01 07:42:28 +00:00
|
|
|
if 0 == mathrand.Intn(2) {
|
|
|
|
typ = "PRIVATE KEY"
|
2020-08-01 07:32:17 +00:00
|
|
|
bytes, err = x509.MarshalPKCS8PrivateKey(k)
|
|
|
|
if nil != err {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else {
|
2020-08-01 07:42:28 +00:00
|
|
|
typ = "RSA PRIVATE KEY"
|
2020-08-01 07:32:17 +00:00
|
|
|
bytes = x509.MarshalPKCS1PrivateKey(k)
|
|
|
|
}
|
|
|
|
return &pem.Block{
|
|
|
|
Type: typ,
|
|
|
|
Bytes: bytes,
|
|
|
|
}, nil
|
|
|
|
case *ecdsa.PrivateKey:
|
2020-08-01 07:42:28 +00:00
|
|
|
if 0 == mathrand.Intn(2) {
|
|
|
|
typ = "PRIVATE KEY"
|
2020-08-01 07:32:17 +00:00
|
|
|
bytes, err = x509.MarshalPKCS8PrivateKey(k)
|
|
|
|
} else {
|
2020-08-01 07:42:28 +00:00
|
|
|
typ = "EC PRIVATE KEY"
|
2020-08-01 07:32:17 +00:00
|
|
|
bytes, err = x509.MarshalECPrivateKey(k)
|
|
|
|
}
|
|
|
|
if nil != err {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &pem.Block{
|
|
|
|
Type: typ,
|
|
|
|
Bytes: bytes,
|
|
|
|
}, nil
|
|
|
|
default:
|
|
|
|
// this is unreachable because we know the types that we pass in
|
|
|
|
log.Printf("keytype: %t, %+v\n", privkey, privkey)
|
|
|
|
panic(keypairs.ErrInvalidPublicKey)
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalPEMPrivateKey outputs the given private key as ASN.1 PEM
|
|
|
|
func MarshalPEMPrivateKey(privkey keypairs.PrivateKey) ([]byte, error) {
|
|
|
|
block, err := marshalDERPrivateKey(privkey)
|
|
|
|
if nil != err {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return pem.EncodeToMemory(block), nil
|
|
|
|
}
|
|
|
|
|
2020-07-25 09:13:19 +00:00
|
|
|
// MarshalECPrivateKey will output the given private key as JWK
|
|
|
|
func MarshalECPrivateKey(k *ecdsa.PrivateKey) []byte {
|
|
|
|
crv := k.Curve.Params().Name
|
|
|
|
d := base64.RawURLEncoding.EncodeToString(k.D.Bytes())
|
|
|
|
x := base64.RawURLEncoding.EncodeToString(k.X.Bytes())
|
|
|
|
y := base64.RawURLEncoding.EncodeToString(k.Y.Bytes())
|
|
|
|
return []byte(fmt.Sprintf(
|
|
|
|
`{"crv":%q,"d":%q,"kty":"EC","x":%q,"y":%q}`,
|
|
|
|
crv, d, x, y,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalRSAPrivateKey will output the given private key as JWK
|
|
|
|
func MarshalRSAPrivateKey(pk *rsa.PrivateKey) []byte {
|
|
|
|
e := base64.RawURLEncoding.EncodeToString(big.NewInt(int64(pk.E)).Bytes())
|
|
|
|
n := base64.RawURLEncoding.EncodeToString(pk.N.Bytes())
|
|
|
|
d := base64.RawURLEncoding.EncodeToString(pk.D.Bytes())
|
|
|
|
p := base64.RawURLEncoding.EncodeToString(pk.Primes[0].Bytes())
|
|
|
|
q := base64.RawURLEncoding.EncodeToString(pk.Primes[1].Bytes())
|
|
|
|
dp := base64.RawURLEncoding.EncodeToString(pk.Precomputed.Dp.Bytes())
|
|
|
|
dq := base64.RawURLEncoding.EncodeToString(pk.Precomputed.Dq.Bytes())
|
|
|
|
qi := base64.RawURLEncoding.EncodeToString(pk.Precomputed.Qinv.Bytes())
|
|
|
|
return []byte(fmt.Sprintf(
|
|
|
|
`{"d":%q,"dp":%q,"dq":%q,"e":%q,"kty":"RSA","n":%q,"p":%q,"q":%q,"qi":%q}`,
|
|
|
|
d, dp, dq, e, n, p, q, qi,
|
|
|
|
))
|
|
|
|
}
|