Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Prev Previous commit
Next Next commit
webcrypto: added X.509 RSA certificate check
  • Loading branch information
r-l-x committed Apr 20, 2018
commit 2b720aa5643127307604977c520e808893a01fbc
115 changes: 70 additions & 45 deletions compiler/natives/src/crypto/x509/x509.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package x509
import (
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"encoding/asn1"
"encoding/base64"
"errors"
Expand Down Expand Up @@ -35,77 +36,101 @@ func padLeft(buf []byte, length int) []byte {
return res
}

// Converts a Go ecdsa.PublicKey to a JavaScript CryptoKey
func ecdsaPubKey2CryptoKey(pub *ecdsa.PublicKey) (*js.Object, error) {
// Converts a Go crypto.PublicKey to a JavaScript CryptoKey
func pubKey2CryptoKey(publicKey crypto.PublicKey) (*js.Object, error) {
format := "jwk"
// Json Web Key (https://tools.ietf.org/html/rfc7517, https://tools.ietf.org/html/rfc7518)
var jwkKey, algorithm js.M

order := len(pub.Params().P.Bytes())
paddedX := padLeft(pub.X.Bytes(), order)
paddedY := padLeft(pub.Y.Bytes(), order)
jwkKey := js.M{
"kty": "EC",
"crv": pub.Params().Name,
"x": base64.RawURLEncoding.EncodeToString(paddedX),
"y": base64.RawURLEncoding.EncodeToString(paddedY),
}
switch pub := publicKey.(type) {
case *ecdsa.PublicKey:
order := len(pub.Params().P.Bytes())
paddedX := padLeft(pub.X.Bytes(), order)
paddedY := padLeft(pub.Y.Bytes(), order)
jwkKey = js.M{
"kty": "EC",
"crv": pub.Params().Name,
"x": base64.RawURLEncoding.EncodeToString(paddedX),
"y": base64.RawURLEncoding.EncodeToString(paddedY),
}

algorithm := js.M{
"name": "ECDSA",
"namedCurve": pub.Params().Name,
algorithm = js.M{
"name": "ECDSA",
"namedCurve": pub.Params().Name,
}
case *rsa.PublicKey:
jwkKey = js.M{
"kty": "RSA",
"n": base64.RawURLEncoding.EncodeToString(pub.N.Bytes()),
"e": base64.RawURLEncoding.EncodeToString(big.NewInt(int64(pub.E)).Bytes()),
}

algorithm = js.M{"name": "RSA"}
default:
return nil, ErrUnsupportedAlgorithm
}

return webcrypto.SubtleCall("importKey", format, jwkKey, algorithm, false, []string{"verify"})
}

func webCryptoCheckSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) error {
cryptoKey, err := pubKey2CryptoKey(publicKey)
if err != nil {
return err
}
var algoName, hashAlgoName string
var webCryptoSig []byte

switch algo {
case ECDSAWithSHA1, SHA1WithRSA:
hashAlgoName = "SHA-1"
case ECDSAWithSHA256, SHA256WithRSA:
hashAlgoName = "SHA-256"
case ECDSAWithSHA384, SHA384WithRSA:
hashAlgoName = "SHA-384"
case ECDSAWithSHA512, SHA512WithRSA:
hashAlgoName = "SHA-512"
default:
return ErrUnsupportedAlgorithm
}

switch pub := publicKey.(type) {
case *ecdsa.PublicKey:
cryptoKey, err := ecdsaPubKey2CryptoKey(pub)
if err != nil {
return err
}
algoName := ""
switch algo {
case ECDSAWithSHA1:
algoName = "SHA-1"
case ECDSAWithSHA256:
algoName = "SHA-256"
case ECDSAWithSHA384:
algoName = "SHA-384"
case ECDSAWithSHA512:
algoName = "SHA-512"
default:
return ErrUnsupportedAlgorithm
}
algoName = "ECDSA"

// We have a ASN1 encoded signature and Web Crypto needs the concatenated padded valued of r and s
sigStruct := new(ecdsaSignature)
_, err = asn1.Unmarshal(signature, sigStruct)
if err != nil {
return err
}

order := len(pub.Params().P.Bytes())
r := padLeft(sigStruct.R.Bytes(), order)
s := padLeft(sigStruct.S.Bytes(), order)
webCryptoSig = append(r, s...)

algorithm := js.M{
"name": "ECDSA",
"hash": js.M{"name": algoName},
}
case *rsa.PublicKey:
algoName = "RSA"
webCryptoSig = signature

res, err := webcrypto.SubtleCall("verify", algorithm, cryptoKey, append(r, s...), signed)
default:
return ErrUnsupportedAlgorithm
}

if err != nil {
return err
}
if !res.Bool() {
return errSignatureCheckFailed
}
return nil
algorithm := js.M{
"name": algoName,
"hash": js.M{"name": hashAlgoName},
}

res, err := webcrypto.SubtleCall("verify", algorithm, cryptoKey, webCryptoSig, signed)

if err != nil {
return err
}
if !res.Bool() {
return errSignatureCheckFailed
}
return ErrUnsupportedAlgorithm
return nil
}

//gopherjs:keep_overridden
Expand Down