Skip to content

Commit

Permalink
spki: support of the format for the ECDH & ECDSA
Browse files Browse the repository at this point in the history
  • Loading branch information
olegbespalov committed Apr 11, 2024
1 parent 2684f5c commit 44a9e53
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
47 changes: 47 additions & 0 deletions webcrypto/elliptic_curve.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ func (e *EcKeyImportParams) ImportKey(
case e.Algorithm.Name == ECDSA && format == RawKeyFormat:
importFn = importECDSAPublicKey
keyType = PublicCryptoKeyType
case e.Algorithm.Name == ECDH && format == SpkiKeyFormat:
importFn = importECDHSPKIPublicKey
keyType = PublicCryptoKeyType
case e.Algorithm.Name == ECDSA && format == SpkiKeyFormat:
importFn = importECDSASPKIPublicKey
keyType = PublicCryptoKeyType
default:
return nil, NewError(NotSupportedError, unsupportedKeyFormatErrorMsg+" "+format+" for algorithm "+e.Algorithm.Name)
}
Expand Down Expand Up @@ -107,6 +113,36 @@ func importECDHPublicKey(curve EllipticCurveKind, keyData []byte) (any, error) {
return handle, nil
}

func importECDHSPKIPublicKey(_ EllipticCurveKind, keyData []byte) (any, error) {
pk, err := x509.ParsePKIXPublicKey(keyData)
if err != nil {
return nil, NewError(DataError, "unable to import ECDH public key data: "+err.Error())
}

ecdsaKey, ok := pk.(*ecdsa.PublicKey)
if !ok {
return nil, NewError(DataError, "a public key is not an ECDSA key")
}

// try to restore the ECDH key
return ecdsaKey.ECDH()
}

func importECDSASPKIPublicKey(_ EllipticCurveKind, keyData []byte) (any, error) {
pk, err := x509.ParsePKIXPublicKey(keyData)
if err != nil {
return nil, NewError(DataError, "unable to import ECDH public key data: "+err.Error())
}

ecdsaKey, ok := pk.(*ecdsa.PublicKey)
if !ok {
return nil, NewError(DataError, "a public key is not an ECDSA key")
}

// try to restore the ECDH key
return ecdsaKey, nil
}

// EllipticCurveKind represents the kind of elliptic curve that is being used.
type EllipticCurveKind string

Expand Down Expand Up @@ -381,6 +417,17 @@ func exportECKey(alg string, ck *CryptoKey, format KeyFormat) ([]byte, error) {
return nil, NewError(OperationError, "unable to extract public key data: "+err.Error())
}

return bytes, nil
case SpkiKeyFormat:
if ck.Type != PublicCryptoKeyType {
return nil, NewError(InvalidAccessError, "key is not a valid elliptic curve public key")
}

bytes, err := x509.MarshalPKIXPublicKey(ck.handle)
if err != nil {
return nil, NewError(OperationError, "unable to marshal key to SPKI format: "+err.Error())
}

return bytes, nil
case Pkcs8KeyFormat:
if ck.Type != PrivateCryptoKeyType {
Expand Down
4 changes: 2 additions & 2 deletions webcrypto/subtle_crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ func (sc *SubtleCrypto) ImportKey(

// 2.
switch format {
case Pkcs8KeyFormat, RawKeyFormat:
case Pkcs8KeyFormat, RawKeyFormat, SpkiKeyFormat:
ab, err := exportArrayBuffer(rt, keyData)
if err != nil {
reject(err)
Expand Down Expand Up @@ -833,7 +833,7 @@ func (sc *SubtleCrypto) ExportKey(format KeyFormat, key goja.Value) *goja.Promis
}

func isBinaryExportedFormat(format KeyFormat) bool {
return format == RawKeyFormat || format == Pkcs8KeyFormat
return format == RawKeyFormat || format == Pkcs8KeyFormat || format == SpkiKeyFormat
}

// WrapKey "wraps" a key.
Expand Down
14 changes: 11 additions & 3 deletions webcrypto/tests/import_export/ec_importKey.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ testVectors.forEach(function(vector) {
[[]].forEach(function(usages) { // Only valid usages argument is empty array
// TODO: return back formats after implementing them
// 'spki', 'spki_compressed', 'jwk', 'raw_compressed'
['raw'].forEach(function(format) {
['raw', 'spki'].forEach(function(format) {
var algorithm = {name: vector.name, namedCurve: curve};
var data = keyData[curve];
if (format === "jwk") { // Not all fields used for public keys
Expand Down Expand Up @@ -116,7 +116,7 @@ function testFormat(format, algorithm, data, keySize, usages, extractable) {
if (compressed) {
[format] = format.split("_compressed");
}
// promise_test(function(test) {
promise_test(function(test) {
return subtle.importKey(format, keyData, algorithm, extractable, usages).
then(function(key) {
// TODO: @olegbespalov consider workaround for making this test pass
Expand All @@ -143,7 +143,7 @@ function testFormat(format, algorithm, data, keySize, usages, extractable) {
assert_unreached("Threw an unexpected error : " + err.toString() + ", format: " + format + " keyData: " + JSON.stringify(keyData) + " algorithm: " + JSON.stringify(algorithm) + " extractable: " + extractable + " usages: " + usages);
}
});
// }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, compressed, keyData, algorithm, extractable, usages));
}, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, compressed, keyData, algorithm, extractable, usages));
}


Expand Down Expand Up @@ -272,6 +272,14 @@ function parameterString(format, compressed, data, algorithm, extractable, usage
return result;
}

function promise_test(fn, name) {
try {
fn();
} catch (e) {
throw Error(`Error in test "${name}": ${e}`);
}
}

// Character representation of any object we may use as a parameter.
function objectToString(obj) {
var keyValuePairs = [];
Expand Down

0 comments on commit 44a9e53

Please sign in to comment.