4bf09f2013-12-27Henrik Grubbström (Grubba) #pike __REAL_VERSION__
e1fb092014-02-14Martin Nilsson #require constant(Nettle.ECC_Curve)
4bf09f2013-12-27Henrik Grubbström (Grubba)  //! Elliptic Curve Cipher Constants. //! //! This module contains constants used with elliptic curve algorithms.
f114c32014-01-16Henrik Grubbström (Grubba) // The module dumper has problems with the overloaded ECDSA class, // so inhibit dumping of this module for now. constant dont_dump_module = 1;
4bf09f2013-12-27Henrik Grubbström (Grubba) //! The definition of an elliptic curve.
3852ef2014-01-04Henrik Grubbström (Grubba) //! //! Objects of this class are typically not created by the user. //! //! @seealso //! @[SECP_192R1], @[SECP_224R1], @[SECP_256R1], @[SECP_384R1], @[SECP_521R1]
4bf09f2013-12-27Henrik Grubbström (Grubba) class Curve { inherit Nettle.ECC_Curve;
e604c62014-01-04Henrik Grubbström (Grubba) 
c6c89b2014-01-13Henrik Grubbström (Grubba) #define BitString Standards.ASN1.Types.BitString
5274582014-01-13Henrik Grubbström (Grubba) #define Identifier Standards.ASN1.Types.Identifier
c6c89b2014-01-13Henrik Grubbström (Grubba) #define Integer Standards.ASN1.Types.Integer #define Object Standards.ASN1.Types.Object #define Sequence Standards.ASN1.Types.Sequence
5b9d5c2015-01-27Henrik Grubbström (Grubba)  protected local int(0..1) `==(mixed x) { if (!objectp(x)) return 0; // NB: Argument order below. return x == ECC_Curve::this; }
5274582014-01-13Henrik Grubbström (Grubba)  //! Returns the PKCS-1 elliptic curve identifier for the curve.
0c4ea52015-08-22Martin Nilsson  //! cf @rfc{5480:2.1.1@}.
5274582014-01-13Henrik Grubbström (Grubba)  Identifier pkcs_named_curve_id()
c6c89b2014-01-13Henrik Grubbström (Grubba)  { switch(name()) { case "SECP_192R1":
5274582014-01-13Henrik Grubbström (Grubba)  return Standards.PKCS.Identifiers.ecc_secp192r1_id;
c6c89b2014-01-13Henrik Grubbström (Grubba)  case "SECP_224R1":
5274582014-01-13Henrik Grubbström (Grubba)  return Standards.PKCS.Identifiers.ecc_secp224r1_id;
c6c89b2014-01-13Henrik Grubbström (Grubba)  case "SECP_256R1":
5274582014-01-13Henrik Grubbström (Grubba)  return Standards.PKCS.Identifiers.ecc_secp256r1_id;
c6c89b2014-01-13Henrik Grubbström (Grubba)  case "SECP_384R1":
5274582014-01-13Henrik Grubbström (Grubba)  return Standards.PKCS.Identifiers.ecc_secp384r1_id;
c6c89b2014-01-13Henrik Grubbström (Grubba)  case "SECP_521R1":
5274582014-01-13Henrik Grubbström (Grubba)  return Standards.PKCS.Identifiers.ecc_secp521r1_id;
c6c89b2014-01-13Henrik Grubbström (Grubba)  } return 0; }
5274582014-01-13Henrik Grubbström (Grubba)  //! Returns the PKCS-1 elliptic curve parameters for the curve.
0c4ea52015-08-22Martin Nilsson  //! cf @rfc{5480:2.1.1@}.
8fe84f2014-01-13Henrik Grubbström (Grubba)  Identifier pkcs_ec_parameters()
5274582014-01-13Henrik Grubbström (Grubba)  {
8fe84f2014-01-13Henrik Grubbström (Grubba)  return pkcs_named_curve_id();
5274582014-01-13Henrik Grubbström (Grubba)  }
0c4ea52015-08-22Martin Nilsson  //! Returns the AlgorithmIdentifier as defined in @rfc{5480:2@}.
c6c89b2014-01-13Henrik Grubbström (Grubba)  Sequence pkcs_algorithm_identifier() { return Sequence( ({ Standards.PKCS.Identifiers.ec_id, pkcs_ec_parameters(), }) ); }
e604c62014-01-04Henrik Grubbström (Grubba)  //! Elliptic Curve Digital Signing Algorithm //! class ECDSA { //! @ignore inherit ::this_program; //! @endignore //! @decl inherit ECC_Curve::ECDSA;
2b50382014-01-13Henrik Grubbström (Grubba)  //! Return the curve.
f4ca2a2015-01-25Martin Nilsson  Curve get_curve()
2b50382014-01-13Henrik Grubbström (Grubba)  { return Curve::this; } //! Return the curve size in bits. int size() { return Curve::size(); }
d145622014-04-13Henrik Grubbström (Grubba)  //! Return the size of the private key in bits. int(0..) key_size() { return Curve::size(); }
e604c62014-01-04Henrik Grubbström (Grubba)  //! Set the private key. //! //! @note //! Throws errors if the key isn't valid for the curve. this_program set_private_key(object(Gmp.mpz)|int k) { ::set_private_key(k); return this; }
581a972017-09-23Henrik Grubbström (Grubba)  //! Set the private key. //! //! @note //! Throws errors if the key isn't valid for the curve. variant this_program set_private_key(string(8bit) k) { return set_private_key(Gmp.mpz(k, 256)); }
e604c62014-01-04Henrik Grubbström (Grubba)  //! Change to the selected point on the curve as public key. //! //! @note //! Throws errors if the point isn't on the curve. this_program set_public_key(object(Gmp.mpz)|int x, object(Gmp.mpz)|int y) { ::set_public_key(x, y); return this; }
46765d2015-01-25Martin Nilsson  //! variant this_program set_public_key(Point p) { ::set_public_key(p->get_x(), p->get_y()); return this; }
ee27be2014-01-13Henrik Grubbström (Grubba)  //! Change to the selected point on the curve as public key. //! //! @param key //! The public key encoded according to ANSI x9.62 4.3.6. //! //! @note //! Throws errors if the point isn't on the curve. variant this_program set_public_key(string(8bit) key) { int sz = (size() + 7)>>3; if ((sizeof(key) != 1 + 2*sz) || (key[0] != 4)) { error("Invalid public key for curve.\n"); } object(Gmp.mpz)|int x; object(Gmp.mpz)|int y; sscanf(key, "%*c%" + sz + "c%" + sz + "c", x, y); ::set_public_key(x, y); return this; }
7c383a2014-02-22Henrik Grubbström (Grubba)  //! Compares the public key in this object with that in the provided //! ECDSA object. int(0..1) public_key_equal(this_program ecdsa) {
f4ca2a2015-01-25Martin Nilsson  return ecdsa->get_curve() == Curve::this &&
7c383a2014-02-22Henrik Grubbström (Grubba)  ecdsa->get_x() == get_x() && ecdsa->get_y() == get_y(); } //! Compares the keys of this ECDSA object with something other. protected int(0..1) _equal(mixed other) { if (!objectp(other) || (object_program(other) != object_program(this)) || !public_key_equal([object(this_program)]other)) { return 0; } this_program ecdsa = [object(this_program)]other; return get_private_key() == ecdsa->get_private_key(); }
e604c62014-01-04Henrik Grubbström (Grubba)  //! Set the random function, used to generate keys and parameters, //! to the function @[r]. this_program set_random(function(int:string(8bit)) r) { ::set_random(r); return this; } //! Generate a new set of private and public keys on the current curve. this_program generate_key() { ::generate_key(); return this; }
c6c89b2014-01-13Henrik Grubbström (Grubba)  //! Get the ANSI x9.62 4.3.6 encoded uncompressed public key. string(8bit) get_public_key() {
46765d2015-01-25Martin Nilsson  return Point(get_x(),get_y())->encode(); } //! Get the public key curve point. Point get_point() { return Point(get_x(), get_y());
c6c89b2014-01-13Henrik Grubbström (Grubba)  }
0c5eaa2016-04-14Henrik Grubbström (Grubba)  //! Get the JWS algorithm identifier for a hash. //! //! @returns //! Returns @expr{0@} (zero) on failure. //! //! @seealso //! @rfc{7518:3.1@} string(7bit) jwa(.Hash hash) { switch(Curve::name() + ":" + hash->name()) { case "SECP_256R1:sha256": return "ES256"; case "SECP_384R1:sha384": return "ES384"; case "SECP_521R1:sha512": return "ES512"; } return 0; }
e604c62014-01-04Henrik Grubbström (Grubba)  //! Signs the @[message] with a PKCS-1 signature using hash algorithm //! @[h]. string(8bit) pkcs_sign(string(8bit) message, .Hash h) {
c6c89b2014-01-13Henrik Grubbström (Grubba)  array sign = map(raw_sign(h->hash(message)), Integer); return Sequence(sign)->get_der();
e604c62014-01-04Henrik Grubbström (Grubba)  }
873c992014-12-23Henrik Grubbström (Grubba)  // FIXME: Consider implementing RFC 6979.
e604c62014-01-04Henrik Grubbström (Grubba)  //! Verify PKCS-1 signature @[sign] of message @[message] using hash //! algorithm @[h]. int(0..1) pkcs_verify(string(8bit) message, .Hash h, string(8bit) sign) {
1591ba2014-09-30Martin Nilsson  Object a = Standards.ASN1.Decode.secure_der_decode(sign);
e604c62014-01-04Henrik Grubbström (Grubba)  // The signature is the DER-encoded ASN.1 sequence Ecdsa-Sig-Value // with the two integers r and s. See RFC 4492 section 5.4. if (!a || (a->type_name != "SEQUENCE") || (sizeof([array]a->elements) != 2) || (sizeof( ([array(object(Object))]a->elements)->type_name - ({ "INTEGER" })))) return 0; return raw_verify(h->hash(message), [object(Gmp.mpz)]([array(object(Object))]a->elements)[0]-> value, [object(Gmp.mpz)]([array(object(Object))]a->elements)[1]-> value); }
63eb552016-04-19Henrik Grubbström (Grubba)  //! Signs the @[message] with a JOSE JWS ECDSA signature using hash //! algorithm @[h]. //! //! @param message //! Message to sign. //! //! @param h //! Hash algorithm to use. //! //! @returns //! Returns the signature on success, and @expr{0@} (zero) //! on failure. //! //! @seealso //! @[pkcs_verify()], @[salt_size()], @rfc{7515@} string(7bit) jose_sign(string(8bit) message, .Hash|void h, mapping(string(7bit):string(7bit)|int)|void headers) { if (!h) { switch(Curve::name()) { case "SECP_256R1": h = .SHA256; break;
7d7d0e2016-04-19Martin Nilsson #if constant(Nettle.SHA384) case "SECP_384R1":
63eb552016-04-19Henrik Grubbström (Grubba)  h = .SHA384;
7d7d0e2016-04-19Martin Nilsson  break; #endif #if constant(Nettle.SHA512)
63eb552016-04-19Henrik Grubbström (Grubba)  case "SECP_521R1": h = .SHA512; break;
7d7d0e2016-04-19Martin Nilsson #endif default:
63eb552016-04-19Henrik Grubbström (Grubba)  return 0; } } string(7bit) alg = jwa(h); if (!alg) return 0; headers = headers || ([]); headers += ([ "alg": alg ]); string(7bit) tbs = sprintf("%s.%s", MIME.encode_base64url(string_to_utf8(Standards.JSON.encode(headers))), MIME.encode_base64url(message)); array(Gmp.mpz) raw = raw_sign(h->hash(tbs));
6e76202016-07-07Henrik Grubbström (Grubba)  int bytes = ((size()+7)>>3); string(8bit) raw_bin = sprintf("%*c%*c", bytes, raw[0], bytes, raw[1]);
63eb552016-04-19Henrik Grubbström (Grubba)  return sprintf("%s.%s", tbs, MIME.encode_base64url(raw_bin)); } //! Verify and decode a JOSE JWS ECDSA signed value. //! //! @param jws //! A JSON Web Signature as returned by @[jose_sign()]. //! //! @returns //! Returns @expr{0@} (zero) on failure, and an array //! @array
7842e92016-05-30Magnus Holmgren  //! @elem mapping(string(7bit):string(7bit)|int) 0
63eb552016-04-19Henrik Grubbström (Grubba)  //! The JOSE header.
7842e92016-05-30Magnus Holmgren  //! @elem string(8bit) 1
63eb552016-04-19Henrik Grubbström (Grubba)  //! The signed message. //! @endarray //! //! @seealso //! @[pkcs_verify()], @rfc{7515:3.5@} array(mapping(string(7bit): string(7bit)|int)|string(8bit)) jose_decode(string(7bit) jws) { array(string(7bit)) segments = [array(string(7bit))](jws/"."); if (sizeof(segments) != 3) return 0; mapping(string(7bit):string(7bit)|int) headers; catch { headers = [mapping(string(7bit):string(7bit)|int)](mixed) Standards.JSON.decode(utf8_to_string(MIME.decode_base64url(segments[0]))); if (!mappingp(headers)) return 0; .Hash h; switch(headers->alg) {
7d7d0e2016-04-19Martin Nilsson  case "ES256":
63eb552016-04-19Henrik Grubbström (Grubba)  h = .SHA256; break; #if constant(Nettle.SHA384)
7d7d0e2016-04-19Martin Nilsson  case "ES384":
63eb552016-04-19Henrik Grubbström (Grubba)  h = .SHA384; break; #endif #if constant(Nettle.SHA512)
7d7d0e2016-04-19Martin Nilsson  case "ES512":
63eb552016-04-19Henrik Grubbström (Grubba)  h = .SHA512;
7d7d0e2016-04-19Martin Nilsson  break;
63eb552016-04-19Henrik Grubbström (Grubba) #endif
7d7d0e2016-04-19Martin Nilsson  default:
63eb552016-04-19Henrik Grubbström (Grubba)  return 0; } string(7bit) tbs = sprintf("%s.%s", segments[0], segments[1]); string(8bit) sign = MIME.decode_base64url(segments[2]); if (raw_verify(h->hash(tbs), Gmp.mpz(sign[..<sizeof(sign)/2], 256), Gmp.mpz(sign[sizeof(sign)/2..], 256))) { return ({ headers, MIME.decode_base64url(segments[1]) }); } }; return 0; }
c6c89b2014-01-13Henrik Grubbström (Grubba)  //! Returns the PKCS-1 algorithm identifier for ECDSA and the provided
a32ced2014-04-12Henrik Grubbström (Grubba)  //! hash algorithm. Only SHA-1 and SHA-2 based hashes are supported //! currently.
c6c89b2014-01-13Henrik Grubbström (Grubba)  Sequence pkcs_signature_algorithm_id(.Hash hash) { switch(hash->name()) {
a32ced2014-04-12Henrik Grubbström (Grubba)  case "sha1": return Sequence( ({ Standards.PKCS.Identifiers.ecdsa_sha1_id }) );
c6c89b2014-01-13Henrik Grubbström (Grubba)  case "sha224": return Sequence( ({ Standards.PKCS.Identifiers.ecdsa_sha224_id }) ); case "sha256": return Sequence( ({ Standards.PKCS.Identifiers.ecdsa_sha256_id }) ); case "sha384": return Sequence( ({ Standards.PKCS.Identifiers.ecdsa_sha384_id }) ); case "sha512": return Sequence( ({ Standards.PKCS.Identifiers.ecdsa_sha512_id }) ); } return 0; }
0c4ea52015-08-22Martin Nilsson  //! Returns the AlgorithmIdentifier as defined in //! @rfc{5480:2.1.1@} including the ECDSA parameters.
c6c89b2014-01-13Henrik Grubbström (Grubba)  Sequence pkcs_algorithm_identifier() { return Curve::pkcs_algorithm_identifier(); } //! Creates a SubjectPublicKeyInfo ASN.1 sequence for the object.
7baea72018-03-07Henrik Grubbström (Grubba)  //! See @rfc{5280:4.1.2.7@} and @rfc{5480:2.2@}.
c6c89b2014-01-13Henrik Grubbström (Grubba)  Sequence pkcs_public_key() { return Sequence(({ pkcs_algorithm_identifier(), BitString(get_public_key()), })); } #undef Sequence
e604c62014-01-04Henrik Grubbström (Grubba) #undef Object
c6c89b2014-01-13Henrik Grubbström (Grubba) #undef Integer
5274582014-01-13Henrik Grubbström (Grubba) #undef Identifier
c6c89b2014-01-13Henrik Grubbström (Grubba) #undef BitString
65be772017-09-21Henrik Grubbström (Grubba)  //! Generate a JWK-style mapping of the object. //! //! @param private_key //! If true, include the private key in the result. //! //! @returns //! Returns a JWK-style mapping on success, and @expr{0@} (zero) //! on failure. //! //! @seealso //! @[create()], @[Web.encode_jwk()], @rfc{7517:4@}, @rfc{7518:6.2@} mapping(string(7bit):string(7bit)) jwk(int(0..1)|void private_key) { if (!jose_name()) return 0; // Not supported for this curve. mapping(string(7bit):string(7bit)) jwk = ([ "kty":"EC", "crv":jose_name(), "x": MIME.encode_base64url(get_x_str()), "y": MIME.encode_base64url(get_y_str()), ]); if (private_key) { // FIXME: Detect if the private key hasn't been set. jwk->d = MIME.encode_base64url(get_private_key()->digits(256)); } return jwk; }
e604c62014-01-04Henrik Grubbström (Grubba)  }
4bf09f2013-12-27Henrik Grubbström (Grubba) }
11d5272014-01-04Henrik Grubbström (Grubba) //! @module SECP_192R1 //! @decl inherit Curve //! @endmodule //! @module SECP_224R1 //! @decl inherit Curve //! @endmodule //! @module SECP_256R1 //! @decl inherit Curve //! @endmodule //! @module SECP_384R1 //! @decl inherit Curve //! @endmodule //! @module SECP_521R1 //! @decl inherit Curve //! @endmodule //! @ignore
21071f2016-09-23Henrik Grubbström (Grubba) #if constant(Nettle.SECP192R1)
a8acae2015-01-27Martin Nilsson Curve SECP_192R1 = Curve(Nettle.SECP192R1);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* constant(Nettle.SECP192R1) */ #if constant(Nettle.SECP224R1)
a8acae2015-01-27Martin Nilsson Curve SECP_224R1 = Curve(Nettle.SECP224R1);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* constant(Nettle.SECP224R1) */ #if constant(Nettle.SECP256R1)
a8acae2015-01-27Martin Nilsson Curve SECP_256R1 = Curve(Nettle.SECP256R1);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* constant(Nettle.SECP256R1) */ #if constant(Nettle.SECP384R1)
a8acae2015-01-27Martin Nilsson Curve SECP_384R1 = Curve(Nettle.SECP384R1);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* constant(Nettle.SECP384R1) */ #if constant(Nettle.SECP521R1)
a8acae2015-01-27Martin Nilsson Curve SECP_521R1 = Curve(Nettle.SECP521R1);
21071f2016-09-23Henrik Grubbström (Grubba) #endif /* constant(Nettle.SECP521R1) */
11d5272014-01-04Henrik Grubbström (Grubba) //! @endignore
f05d052016-10-08Henrik Grubbström (Grubba) 
c758ac2017-03-25Henrik Grubbström (Grubba) #if constant(Nettle.Curve25519)
f05d052016-10-08Henrik Grubbström (Grubba) //! @module Curve25519
c758ac2017-03-25Henrik Grubbström (Grubba) //! //! The definition of the elliptic curve X25519. //! //! @seealso //! @[Curve] //! @ignore class _Curve25519 { //! @endignore
f05d052016-10-08Henrik Grubbström (Grubba) 
c758ac2017-03-25Henrik Grubbström (Grubba)  //! @decl inherit Nettle.Curve25519 inherit Nettle.Curve25519;
f05d052016-10-08Henrik Grubbström (Grubba) 
c758ac2017-03-25Henrik Grubbström (Grubba) #define BitString Standards.ASN1.Types.BitString #define Identifier Standards.ASN1.Types.Identifier #define Integer Standards.ASN1.Types.Integer #define Object Standards.ASN1.Types.Object #define Sequence Standards.ASN1.Types.Sequence protected local int(0..1) `==(mixed x) { if (!objectp(x)) return 0; // NB: Argument order below. return x == Curve25519::this; } //! Returns the PKCS-1 elliptic curve identifier for the curve. //! cf @rfc{5480:2.1.1@}. Identifier pkcs_named_curve_id() { return Standards.PKCS.Identifiers.x25519_id; } //! Returns the AlgorithmIdentifier as defined in @rfc{5480:2@}. Sequence pkcs_algorithm_identifier() { return Sequence( ({ Standards.PKCS.Identifiers.x25519_id, }) ); }
6a5cad2017-10-10Henrik Grubbström (Grubba)  //! Edwards Curve Digital Signing Algorithm
c758ac2017-03-25Henrik Grubbström (Grubba)  //! class EdDSA { //! @decl inherit Curve25519::EdDSA; //! @ignore inherit ::this_program; //! @endignore //! Return the curve. _Curve25519 get_curve() { return _Curve25519::this; } //! Return the curve size in bits. int size() { return _Curve25519::size(); } //! Return the size of the private key in bits. int(0..) key_size() { return _Curve25519::size(); }
3f2bd62017-08-29Henrik Grubbström (Grubba)  //! Set the private key. //! //! @note //! Throws errors if the key isn't valid for the curve. this_program set_private_key(string(8bit) k) { ::set_private_key(k); return this; }
c758ac2017-03-25Henrik Grubbström (Grubba)  //! this_program set_public_key(string(8bit) key) { ::set_public_key(key); return this; } //! variant this_program set_public_key(Point p) { ::set_public_key(p->get_x()); return this; } //! Compares the public key in this object with that in the provided //! ECDSA object. int(0..1) public_key_equal(this_program eddsa) { return eddsa->get_curve() == _Curve25519::this && eddsa->get_x() == get_x() && eddsa->get_y() == get_y(); } //! Compares the keys of this ECDSA object with something other. protected int(0..1) _equal(mixed other) { if (!objectp(other) || (object_program(other) != object_program(this)) || !public_key_equal([object(this_program)]other)) { return 0; } this_program eddsa = [object(this_program)]other; return get_private_key() == eddsa->get_private_key(); } //! Set the random function, used to generate keys and parameters, //! to the function @[r]. this_program set_random(function(int:string(8bit)) r) { ::set_random(r); return this; } //! Generate a new set of private and public keys on the current curve. this_program generate_key() { ::generate_key(); return this; } //! Get the ANSI x9.62 4.3.6 encoded uncompressed public key. string(8bit) get_public_key() { return get_x(); } //! Get the public key curve point. Point get_point() { return Point(get_x(), get_y()); } //! Get the JWS algorithm identifier for a hash. //! //! @param hash //! Hash algorithm; ignored for Ed25519. //! //! @returns //! Returns @expr{0@} (zero) on failure. //! //! @seealso //! @rfc{7518:3.1@} string(7bit) jwa(.Hash|void hash) { return "EdDSA"; } //! Signs the @[message] with a PKCS-1 signature using hash algorithm //! @[h]. //! //! @param h //! Hash algorithm; ignored for @[Curve25519]. string(8bit) pkcs_sign(string(8bit) message, .Hash|void h) { return raw_sign(message); } // FIXME: Consider implementing RFC 6979. //! Verify PKCS-1 signature @[sign] of message @[message] using hash //! algorithm @[h]. //! //! @param h //! Hash algorithm; ignored for Ed25519. int(0..1) pkcs_verify(string(8bit) message, .Hash|void h, string(8bit) sign) { // The signature is the raw signature string. return raw_verify(message, sign); } //! Signs the @[message] with a JOSE JWS EdDSA signature. //! //! @param message //! Message to sign. //! //! @param h //! Hash algorithm to use; ignored for Ed25519. //! //! @returns //! Returns the signature on success, and @expr{0@} (zero) //! on failure. //! //! @seealso //! @[pkcs_verify()], @[salt_size()], @rfc{7515@} string(7bit) jose_sign(string(8bit) message, .Hash|void h, mapping(string(7bit):string(7bit)|int)|void headers) { string(7bit) alg = jwa(h); if (!alg) return 0; headers = headers || ([]); headers += ([ "alg": alg ]); string(7bit) tbs = sprintf("%s.%s", MIME.encode_base64url(string_to_utf8(Standards.JSON.encode(headers))), MIME.encode_base64url(message)); string(8bit) raw_bin = raw_sign(tbs); return sprintf("%s.%s", tbs, MIME.encode_base64url(raw_bin)); } //! Verify and decode a JOSE JWS EdDSA signed value. //! //! @param jws //! A JSON Web Signature as returned by @[jose_sign()]. //! //! @returns //! Returns @expr{0@} (zero) on failure, and an array //! @array //! @elem mapping(string(7bit):string(7bit)|int) 0 //! The JOSE header. //! @elem string(8bit) 1 //! The signed message. //! @endarray //! //! @seealso //! @[pkcs_verify()], @rfc{7515:3.5@} array(mapping(string(7bit): string(7bit)|int)|string(8bit)) jose_decode(string(7bit) jws) { array(string(7bit)) segments = [array(string(7bit))](jws/"."); if (sizeof(segments) != 3) return 0; mapping(string(7bit):string(7bit)|int) headers; catch { headers = [mapping(string(7bit):string(7bit)|int)](mixed) Standards.JSON.decode(utf8_to_string(MIME.decode_base64url(segments[0]))); if (!mappingp(headers)) return 0; if (headers->alg != "EdDSA") return 0; string(7bit) tbs = sprintf("%s.%s", segments[0], segments[1]); string(8bit) sign = MIME.decode_base64url(segments[2]); if (raw_verify(tbs, sign)) { return ({ headers, MIME.decode_base64url(segments[1]) }); } }; return 0; } //! Returns the EdDSA identifier for the curve. Identifier pkcs_named_curve_id() { return Standards.PKCS.Identifiers.eddsa25519_id; } //! Returns the PKCS-1 algorithm identifier for EdDSA and the provided //! hash algorithm. //! //! @param hash //! Hash algorithm; ignored for @[Curve25519]. Sequence pkcs_signature_algorithm_id(.Hash|void hash) { return Sequence( ({ Standards.PKCS.Identifiers.eddsa25519_id }) ); } //! Returns the AlgorithmIdentifier as defined in //! @rfc{5480:2.1.1@} including the EdDSA parameters. Sequence pkcs_algorithm_identifier() { return Sequence( ({ Standards.PKCS.Identifiers.eddsa25519_id }) ); } //! Creates a SubjectPublicKeyInfo ASN.1 sequence for the object. //! See @rfc{5280:4.1.2.7@}. Sequence pkcs_public_key() { return Sequence(({ pkcs_algorithm_identifier(), BitString(get_public_key()), })); } #undef Sequence #undef Object #undef Integer #undef Identifier #undef BitString
731e3d2017-09-29Henrik Grubbström (Grubba)  //! Generate a JWK-style mapping of the object. //! //! @param private_key //! If true, include the private key in the result. //! //! @returns //! Returns a JWK-style mapping on success, and @expr{0@} (zero) //! on failure. //! //! @seealso //! @[create()], @[Web.encode_jwk()], @rfc{8037@} mapping(string(7bit):string(7bit)) jwk(int(0..1)|void private_key) { if (!jose_name()) return 0; // Not supported for this curve. mapping(string(7bit):string(7bit)) jwk = ([ "kty":"OKP", "crv":jose_name(), "x": MIME.encode_base64url(get_x_str()), ]); if (private_key) { // FIXME: Detect if the private key hasn't been set. jwk->d = MIME.encode_base64url(get_private_key()); } return jwk; }
c758ac2017-03-25Henrik Grubbström (Grubba)  } }
f05d052016-10-08Henrik Grubbström (Grubba)  //! @ignore
c758ac2017-03-25Henrik Grubbström (Grubba) Nettle.Curve25519 Curve25519 = _Curve25519();
f05d052016-10-08Henrik Grubbström (Grubba) //! @endignore
c758ac2017-03-25Henrik Grubbström (Grubba)  //! @endmodule #endif /* constant(Nettle.Curve25519) */