Move JWK base64 decoding to JSON parsing step

This commit is contained in:
Tulir Asokan 2023-07-16 13:33:51 +03:00
parent 360fe208a8
commit e6cec49353
4 changed files with 45 additions and 75 deletions

View file

@ -1,6 +1,9 @@
package libgm
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
@ -333,9 +336,10 @@ func (c *Client) refreshAuthToken() error {
requestID := uuid.NewString()
timestamp := time.Now().UnixMilli() * 1000
sig, sigErr := jwk.SignRequest(requestID, int64(timestamp))
if sigErr != nil {
return sigErr
signBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%d", requestID, timestamp)))
sig, err := ecdsa.SignASN1(rand.Reader, jwk.GetPrivateKey(), signBytes[:])
if err != nil {
return err
}
payloadMessage, messageErr := payload.RegisterRefresh(sig, requestID, int64(timestamp), c.authData.DevicePair.Browser, c.authData.TachyonAuthToken)

View file

@ -4,84 +4,51 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"fmt"
"math/big"
)
type RawURLBytes []byte
func (rub RawURLBytes) MarshalJSON() ([]byte, error) {
out := make([]byte, 2+base64.RawURLEncoding.EncodedLen(len(rub)))
out[0] = '"'
base64.RawURLEncoding.Encode(out[1:], rub)
out[len(out)-1] = '"'
return out, nil
}
func (rub *RawURLBytes) UnmarshalJSON(in []byte) error {
if len(in) < 2 || in[0] != '"' || in[len(in)-1] != '"' {
return fmt.Errorf("invalid value for RawURLBytes: not a JSON string")
}
*rub = make([]byte, base64.RawURLEncoding.DecodedLen(len(in)-2))
_, err := base64.RawURLEncoding.Decode(*rub, in[1:len(in)-1])
return err
}
type JWK struct {
KeyType string `json:"kty"`
Curve string `json:"crv"`
D string `json:"d"`
X string `json:"x"`
Y string `json:"y"`
KeyType string `json:"kty"`
Curve string `json:"crv"`
D RawURLBytes `json:"d"`
X RawURLBytes `json:"x"`
Y RawURLBytes `json:"y"`
}
func (t *JWK) GetPrivateKey() (*ecdsa.PrivateKey, error) {
curve := elliptic.P256()
xBytes, err := base64.RawURLEncoding.DecodeString(t.X)
if err != nil {
return nil, err
func (t *JWK) GetPrivateKey() *ecdsa.PrivateKey {
return &ecdsa.PrivateKey{
PublicKey: *t.GetPublicKey(),
D: new(big.Int).SetBytes(t.D),
}
yBytes, err := base64.RawURLEncoding.DecodeString(t.Y)
if err != nil {
return nil, err
}
dBytes, err := base64.RawURLEncoding.DecodeString(t.D)
if err != nil {
return nil, err
}
priv := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: curve,
X: new(big.Int).SetBytes(xBytes),
Y: new(big.Int).SetBytes(yBytes),
},
D: new(big.Int).SetBytes(dBytes),
}
return priv, nil
}
func (t *JWK) GetPublicKey() (*ecdsa.PublicKey, error) {
xBytes, err := base64.RawURLEncoding.DecodeString(t.X)
if err != nil {
return nil, err
}
yBytes, err := base64.RawURLEncoding.DecodeString(t.Y)
if err != nil {
return nil, err
}
x := new(big.Int).SetBytes(xBytes)
y := new(big.Int).SetBytes(yBytes)
pubKey := &ecdsa.PublicKey{
func (t *JWK) GetPublicKey() *ecdsa.PublicKey {
return &ecdsa.PublicKey{
Curve: elliptic.P256(),
X: x,
Y: y,
X: new(big.Int).SetBytes(t.X),
Y: new(big.Int).SetBytes(t.Y),
}
return pubKey, nil
}
func (t *JWK) MarshalX509PublicKey() ([]byte, error) {
pubKey, err := t.GetPublicKey()
if err != nil {
return nil, err
}
return x509.MarshalPKIXPublicKey(pubKey)
}
func (t *JWK) SignRequest(requestID string, timestamp int64) ([]byte, error) {
signBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%d", requestID, timestamp)))
privKey, privErr := t.GetPrivateKey()
if privErr != nil {
return nil, privErr
}
return ecdsa.SignASN1(rand.Reader, privKey, signBytes[:])
}
// GenerateECDSAKey generates a new ECDSA private key with P-256 curve
@ -93,8 +60,8 @@ func GenerateECDSAKey() (*JWK, error) {
return &JWK{
KeyType: "EC",
Curve: "P-256",
D: base64.RawURLEncoding.EncodeToString(privKey.D.Bytes()),
X: base64.RawURLEncoding.EncodeToString(privKey.X.Bytes()),
Y: base64.RawURLEncoding.EncodeToString(privKey.Y.Bytes()),
D: privKey.D.Bytes(),
X: privKey.X.Bytes(),
Y: privKey.Y.Bytes(),
}, nil
}

View file

@ -22,9 +22,6 @@ type Pairer struct {
pairingKey []byte
}
/*
refreshQrCodeTime is the interval to refresh the qr code in seconds, this is usually 20 seconds.
*/
func (c *Client) NewPairer(keyData *crypto.JWK, refreshQrCodeTime int) (*Pairer, error) {
if keyData == nil {
var err error

View file

@ -1,6 +1,8 @@
package payload
import (
"crypto/x509"
"github.com/google/uuid"
"google.golang.org/protobuf/proto"
@ -9,7 +11,7 @@ import (
)
func RegisterPhoneRelay(jwk *crypto.JWK) ([]byte, *binary.AuthenticationContainer, error) {
key, err := jwk.MarshalX509PublicKey()
key, err := x509.MarshalPKIXPublicKey(jwk.GetPublicKey())
if err != nil {
return nil, nil, err
}