ECDSA WTLS-8

74 views
Skip to first unread message

Brendan Jones

unread,
Feb 26, 2015, 8:54:45 AM2/26/15
to cryptop...@googlegroups.com
Hi all,

I was wondering if anyone could tell me if it is in fact possible to verify a signature created using WTLS-8? 
A reference to the specification of this curve can be found here: http://technical.openmobilealliance.org/tech/affiliates/wap/wap-261-wtls-20010406-a.pdf (page 90)

We are currently looking at alternatives to OpenSSL and Crypto++ seems like a good way to go.
I have spent a little time trying to do this in Crypto++ but I have not had any success as yet. Before I go any further I thought I'd ask the knowledgable folk here.

many thanks
B

Jean-Pierre Münch

unread,
Feb 26, 2015, 11:33:14 AM2/26/15
to cryptop...@googlegroups.com
Hey Brendan,

yes, I do think it's possible if the curves are the only critical point.
I do furthermore think that some of the listed curves are already shipped with Crypto++.
Especially this concerns 3,4,7,10 and 11 (if I understood the listing right). Those are also the names under which these curves are available in Crypto++.
Those curves are available with the asn.h header in the asn1 subnamespace.

If you specifically mean the curve #8 of WTLS, it looks like a non-standard curve (not neccessarily a bad thing).
But as you have all the data you need for this task you can simply go ahaed and write a small loader function that constructs you the neccessary curve.
Some sample code that shows you how to load a custom curve is given here.

BR

JPM

Brendan Jones

unread,
Mar 2, 2015, 6:01:27 AM3/2/15
to cryptop...@googlegroups.com


On Thursday, 26 February 2015 17:33:14 UTC+1, Jean-Pierre Münch wrote:
Hey Brendan,

yes, I do think it's possible if the curves are the only critical point.
I do furthermore think that some of the listed curves are already shipped with Crypto++.

OK, thanks for the info. When you say this is the only critical point are you perhaps referring to the hash algorithm used or some other factor?
 
At the moment, all I have is the public key. I can use OpenSSL to dump the output of the public key and can convert it to DER format in Crypto++ and what I pass it through dumpasn1 it matches.  
Following your links what values should I be using for the point Q when both octet string for the public key and the generator are compressed (prefixed with 02 in ASN1 output) ?

eg (I'm not entirely comfortable posting the key in a public forum so I have obfuscated some of the detail here):

Thanks again

Private-Key: (113 bit)

pub:     02:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx

Field Type: prime-field

Prime: 00:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx

A:    0

B:    3 (0x3)

Generator (compressed):

    02:00:00:00:00:00:00:00:00:00:00:00:00:00:01

Order: 

    01:00:00:00:00:00:00:xx:xx:xx:xx:xx:xx:xx:xx

Cofactor:  1 (0x1)






Jeffrey Walton

unread,
Mar 3, 2015, 12:08:02 AM3/3/15
to cryptop...@googlegroups.com

I was wondering if anyone could tell me if it is in fact possible to verify a signature created using WTLS-8? 
A reference to the specification of this curve can be found here: http://technical.openmobilealliance.org/tech/affiliates/wap/wap-261-wtls-20010406-a.pdf (page 90)

From page 64 of the document you cited:

    enum { anonymous(0), ecdsa_sha(1), rsa_sha(2), (255)} SignatureAlgorithm;

You should be OK with rsa_sha, but its not clear to me if all the ecdsa_sha are supported. To understand why, you need to look at Table 8 on page 86 and the curves WTLS calls out. I *think* Crypto++ will support about 8 of the 12 they specify.
 
We are currently looking at alternatives to OpenSSL and Crypto++ seems like a good way to go.
I have spent a little time trying to do this in Crypto++ but I have not had any success as yet. Before I go any further I thought I'd ask the knowledgable folk here.

I think it depends on what you want to accomplish.

Are you interested *only* in verifying a signature that's already been parsed? Or are you interested in the bigger package? Here, the bigger package includes things like implementing the protocol (sub tasks will include asynchronous socket I/O, record layer implementation, X.509 parsing, key exchange, bulk transfer, etc).

If its the former, then Crypto++ should do fine. If the latter, then you are going to have a lot of work because it looks like a re-implementation of TLS. In the case of the latter, you should evaluate another library.

From your other message:


> At the moment, all I have is the public key. I can use OpenSSL to dump
> the output of the public key and can convert it to DER format in Crypto++
> and what I pass it through dumpasn1 it matches...

This should help if its in PEM format: http://www.cryptopp.com/wiki/PEM_Pack. You won't need to use OpenSSL to convert it to ASN.1/DER.


> eg (I'm not entirely comfortable posting the key in a public forum so I
> have obfuscated some of the detail here):

That's fine. Call out the curve you are using from page 88. Or, post the OID, Curve Name or domain parameters (Curve, Base Point and Modulus); keep the Public Point (Q) and the Private Exponent (x) to yourself.

Jeff

Brendan Jones

unread,
Mar 3, 2015, 1:41:37 AM3/3/15
to cryptop...@googlegroups.com


On Tuesday, 3 March 2015 06:08:02 UTC+1, Jeffrey Walton wrote:

I was wondering if anyone could tell me if it is in fact possible to verify a signature created using WTLS-8? 
A reference to the specification of this curve can be found here: http://technical.openmobilealliance.org/tech/affiliates/wap/wap-261-wtls-20010406-a.pdf (page 90)

From page 64 of the document you cited:

    enum { anonymous(0), ecdsa_sha(1), rsa_sha(2), (255)} SignatureAlgorithm;

You should be OK with rsa_sha, but its not clear to me if all the ecdsa_sha are supported. To understand why, you need to look at Table 8 on page 86 and the curves WTLS calls out. I *think* Crypto++ will support about 8 of the 12 they specify.
 
We are currently looking at alternatives to OpenSSL and Crypto++ seems like a good way to go.
I have spent a little time trying to do this in Crypto++ but I have not had any success as yet. Before I go any further I thought I'd ask the knowledgable folk here.

I think it depends on what you want to accomplish.

Are you interested *only* in verifying a signature that's already been parsed? Or are you interested in the bigger package? Here, the bigger package includes things like implementing the protocol (sub tasks will include asynchronous socket I/O, record layer implementation, X.509 parsing, key exchange, bulk transfer, etc).

If its the former, then Crypto++ should do fine. If the latter, then you are going to have a lot of work because it looks like a re-implementation of TLS. In the case of the latter, you should evaluate another library.

Just the ECDSA signature verification. Its a legacy application and we can't change the private key at the other end.The public key does not name a curve but by comparing to the EC params from open ssl and the aforementioned document it looks like wap-wsg-idm-ecid-wtls8 which is not One of the names curves that crypto++ supports, so I will need to construct the curve manually. 

From your other message:

> At the moment, all I have is the public key. I can use OpenSSL to dump
> the output of the public key and can convert it to DER format in Crypto++
> and what I pass it through dumpasn1 it matches...

This should help if its in PEM format: http://www.cryptopp.com/wiki/PEM_Pack. You won't need to use OpenSSL to convert it to ASN.1/DER.

I did try PEM pack and I receive a BER decode error. However if I convert it myself I am able to pass the resulting DER into dumpasn1 and read the key parameters sucessfully.

 
 
> eg (I'm not entirely comfortable posting the key in a public forum so I
> have obfuscated some of the detail here):

That's fine. Call out the curve you are using from page 88. Or, post the OID, Curve Name or domain parameters (Curve, Base Point and Modulus); keep the Public Point (Q) and the Private Exponent (x) to yourself.

Jeff

So I have a few questions - the public key component of starts with 02 (see the openssl output of the key above) which signifies point compression right? Therefore how I can I construct the key in the manner below (taken from the wiki):

Integers p, a and b I can construct from the key output above. However how do I construct points q and g? Do I have to solve for y**2 = x**3 + ax + b over GF(p) ? 
If I assume use the parameters from http://technical.openmobilealliance.org/tech/affiliates/wap/wap-261-wtls-20010406-a.pdf (page 90) have been used I can provide a value for point g which seems to fit.  

ECP curve( p, a, b );
ECP::Point g( gx, gy );    
ECP::Point q( qx, qy );

ECDSA<ECP, SHA1>::PublicKey publicKey;
publicKey.Initialize( curve, g, n, q );

bool result = publicKey.Validate( prng, 3 );
if( !result ) { ... }
Thanks again
Brendan

Jeffrey Walton

unread,
Mar 3, 2015, 6:21:44 PM3/3/15
to cryptop...@googlegroups.com
>> This should help if its in PEM format: http://www.cryptopp.com/wiki/PEM_Pack.
>> You won't need to use OpenSSL to convert it to ASN.1/DER.
>>
> I did try PEM pack and I receive a BER decode error. However if I convert it myself
> I am able to pass the resulting DER into dumpasn1 and read the key parameters
> successfully.

Oh, that's egg on my face since I wrote it.

Can you send me what you have for testing and diagnostics? Or a set of test keys to duplicate the problem?

> So I have a few questions - the public key component of starts with 02 (see the
> openssl output of the key above) which signifies point compression right?

I believe that is correct, but I'd need to see a key to confirm. (I'd probably just dump it with Gutmann's ASN.1 or `openssl asn1` utility).

> However how do I construct points q and g)

You should be given G. Its the generator, and its part of the domain parameters.

x is the private exponent, and Q is the public key. To generate `x`, you pick a random number in [1, p-1] (IIRC). To get Q, you perform Q = xG (IIRC).

Jeff

Jeffrey Walton

unread,
Mar 3, 2015, 6:43:49 PM3/3/15
to cryptop...@googlegroups.com
>> However how do I construct points q and g)
>>
> You should be given G. Its the generator, and its part of the domain parameters.
?
> x is the private exponent, and Q is the public key. To generate `x`, you
> pick a random number in [1, p-1] (IIRC). To get Q, you perform Q = xG (IIRC).

It just occurred to me what you may have been asking....

Use the Initialize() that takes a PRNG. The library will generate x and Q for you.

If you use the Initialize() that lacks the PRNG, then you have to supply x and Q.

Jeff

Brendan Jones

unread,
Mar 3, 2015, 11:12:53 PM3/3/15
to cryptop...@googlegroups.com


On Wednesday, 4 March 2015 00:43:49 UTC+1, Jeffrey Walton wrote:
>> However how do I construct points q and g)
>>
> You should be given G. Its the generator, and its part of the domain parameters.
?
> x is the private exponent, and Q is the public key. To generate `x`, you
> pick a random number in [1, p-1] (IIRC). To get Q, you perform Q = xG (IIRC).

It just occurred to me what you may have been asking....

Use the Initialize() that takes a PRNG. The library will generate x and Q for you.

If you use the Initialize() that lacks the PRNG, then you have to supply x and Q.


Thanks Jeffrey

I believe the PEM pack s fine, its the .Load function that is throwing the BERDecode error. I have tried the following all resulting in BERDecode error on load (experimenting SHA1,SHA224,SHA256 Weak::MD5 etc)
ECDSA<ECP, CryptoPP::SHA>::PublicKey publicKeyDER;

    FileSource fs( "my-der.der", true /*pump all*/ );
    publicKeyDER.Load( fs );
    RandomNumberGenerator prng;
    valid = publicKeyDER.Validate( prng, 3 );

Here is the ASN output. 

openssl asn1parse -in my-der.der -inform DER -dlimit 16
    0:d=0  hl=2 l= 107 cons: SEQUENCE          
    2:d=1  hl=2 l=  87 cons: SEQUENCE          
    4:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
   13:d=2  hl=2 l=  76 cons: SEQUENCE          
   15:d=3  hl=2 l=   1 prim: INTEGER           :01
   18:d=3  hl=2 l=  26 cons: SEQUENCE          
   20:d=4  hl=2 l=   7 prim: OBJECT            :prime-field
   29:d=4  hl=2 l=  15 prim: INTEGER           :FFFFFFFFFFFFFFFFFFFFFFFFFDE7
   46:d=3  hl=2 l=   6 cons: SEQUENCE          
   48:d=4  hl=2 l=   1 prim: OCTET STRING      
      0001 - <SPACES/NULS>
   51:d=4  hl=2 l=   1 prim: OCTET STRING      
      0000 - 03                                                .
   54:d=3  hl=2 l=  15 prim: OCTET STRING      
      0000 - 02 00 00 00 00 00 00 00-00 00 00 00 00 00 01      ...............
   71:d=3  hl=2 l=  15 prim: INTEGER           :0100000000000001ECEA551AD837E9
   88:d=3  hl=2 l=   1 prim: INTEGER           :01
   91:d=1  hl=2 l=  16 prim: BIT STRING        
      0000 - 00 02 XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   ........L......[

and also:

Private-Key: (113 bit)
pub: 
    02:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
Field Type: prime-field
Prime:
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fd:e7
A:    0
B:    3 (0x3)
Generator (compressed):
    02:00:00:00:00:00:00:00:00:00:00:00:00:00:01
Order: 
    01:00:00:00:00:00:00:01:ec:ea:55:1a:d8:37:e9
Cofactor:  1 (0x1)

Jeffrey Walton

unread,
Mar 12, 2015, 3:24:19 AM3/12/15
to cryptop...@googlegroups.com
I was able to produce a private and public keys with the following commands (thanks BJ):

    # Private key
    openssl ecparam -name wap-wsg-idm-ecid-wtls8 -genkey -noout \
    -out wtls8-priv.der -outform DER -conv_form compressed \
    -param_enc named_curve

And:

    # Public key
    openssl ec -in wtls8-priv.der -inform DER -outform DER \
    -conv_form compressed -out wtls8-pub.der -pubout

Note the use of `-param_enc named_curve`. The named curve is required per RFC 5915. "Named Curve" means you call it by the OID, and not a list of domain parameters.

The following program reads and verifies the public key OK, but it dies on the private key. It needs the OID patch.

    cout << "Loading verifier key..." << endl;
    FileSource fs2("wtls8-pub.der", true);
    verifier.BERDecode(fs2);

    verifier.GetKey().Validate(prng, 3);
    cout << "Validated verifier key..." << endl;

    cout << "Loading signer key..." << endl;
    FileSource fs1("wtls8-priv.der", true);
    signer.BERDecode(fs1);

    signer.GetKey().Validate(prng, 3);
    cout << "Validated signer key..." << endl;

It dies on parsing the private key in PKCS8PrivateKey::BERDecode due to the version check (more below).

According to RFC 5915:

   ECPrivateKey ::= SEQUENCE {
     version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
     privateKey     OCTET STRING,
     parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
     publicKey  [1] BIT STRING OPTIONAL
   }

And:

$ dumpasn1 wtls8-priv.der
  0  62: SEQUENCE {
  2   1:   INTEGER 1
  5  14:   OCTET STRING FD 11 D7 5E E1 72 74 E0 A5 69 A2 6E 69 49
 21   7:   [0] {
 23   5:     OBJECT IDENTIFIER '2 23 43 1 4 8'
       :     }
 30  32:   [1] {
 32  30:     BIT STRING
       :       04 68 0C BA 14 5D D1 FC C1 FE 8A 7E A0 4E 86 58
       :       6E 28 33 FE 2C EF EF 74 E7 ED 61 ED D0
       :     }
       :   }

But Crypto++ wants version 0 (from asn.cpp:548):

    // check version
    BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 0);

Next is to figure out version 0 vs 1.

Jeff

**********
$ gdb ./wtls-test.exe
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./wtls-test.exe...done.
(gdb) b BERDecode
Breakpoint 1 at 0x403a7b: BERDecode. (2 locations)
(gdb) r
Starting program: /home/jwalton/cryptopp-wtls/wtls-test.exe
Loading verifier key...

Breakpoint 1, main (argc=<optimized out>, argv=<optimized out>)
    at wtls-test.c++:50
warning: Source file is more recent than executable.
50            verifier.BERDecode(fs2);
(gdb) c
Continuing.
Validated verifier key...
Loading signer key...

Breakpoint 1, main (argc=<optimized out>, argv=<optimized out>)
    at wtls-test.c++:60
60   
(gdb) s
BERDecode (bt=..., this=0x7fffffffdcf8) at cryptlib.h:1144
1144            {AccessMaterial().Load(bt);}
(gdb)
CryptoPP::PrivateKeyAlgorithm::AccessMaterial (this=0x7fffffffdcf8)
    at cryptlib.h:1168
1168        CryptoMaterial & AccessMaterial() {return AccessPrivateKey();}
(gdb)
CryptoPP::DL_ObjectImplBase<CryptoPP::DL_SignerBase<CryptoPP::ECPPoint>, CryptoPP::DL_SignatureSchemeOptions<CryptoPP::DL_SS<CryptoPP::DL_Keys_ECDSA<CryptoPP::ECP>, CryptoPP::DL_Algorithm_ECDSA<CryptoPP::ECP>, CryptoPP::DL_SignatureMessageEncodingMethod_DSA, CryptoPP::SHA1, int>, CryptoPP::DL_Keys_ECDSA<CryptoPP::ECP>, CryptoPP::DL_Algorithm_ECDSA<CryptoPP::ECP>, CryptoPP::DL_SignatureMessageEncodingMethod_DSA, CryptoPP::SHA1>, CryptoPP::DL_PrivateKey_WithSignaturePairwiseConsistencyTest<CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP>, CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256> > >::AccessPrivateKey (this=0x7fffffffdcf0)
    at pubkey.h:1287
1287        PrivateKey & AccessPrivateKey() {return m_key;}
(gdb)
CryptoPP::ASN1CryptoMaterial<CryptoPP::PrivateKey>::Load (this=0x7fffffffdd10,
    bt=...) at asn.h:254
254        void Load(BufferedTransformation &bt)
(gdb)
255            {BERDecode(bt);}
(gdb)
CryptoPP::PKCS8PrivateKey::BERDecode (this=0x7fffffffdd10, bt=...)
    at asn.cpp:548
548    {
(gdb) l
543   
544        subjectPublicKeyInfo.MessageEnd();
545    }
546   
547    void PKCS8PrivateKey::BERDecode(BufferedTransformation &bt)
548    {
549        BERSequenceDecoder privateKeyInfo(bt);
550            word32 version;
551            BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 0);    // check version
552   
(gdb) n
549        BERSequenceDecoder privateKeyInfo(bt);
(gdb)
551            BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 0);    // check version
(gdb)
BER decode error
[Inferior 1 (process 29485) exited with code 01]

**********

here are some BERDecodeUnsigned:

$ grep -A 1 BERDecodeUnsigned *
asn.h:void BERDecodeUnsigned(BufferedTransformation &in, T &w, byte asnTag = INTEGER,
asn.h-                       T minValue = 0, T maxValue = 0xffffffff)
--
asn.cpp:        BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 0);    // check version
--
ec2n.cpp:    BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1);
--
eccrypto.cpp:            BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1);    // check version
--
eccrypto.cpp:        BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1);// check version
--
eprecomp.cpp:    BERDecodeUnsigned<word32>(seq, version, INTEGER, 1, 1);
--
pem-rd.cpp:    BERDecodeUnsigned<word32>(seq, v, INTEGER, 0, 0);    // check version

**********

Jeffrey Walton

unread,
Mar 12, 2015, 5:19:25 AM3/12/15
to cryptop...@googlegroups.com
> The following program reads and verifies the public key OK, but
> it dies on the private key. It needs the OID patch...

>
> Next is to figure out version 0 vs 1.

Here's the code you need to use to call to decode the private key. BERDecodePrivateKey routes to DL_PrivateKey_EC<EC>::BERDecodePrivateKey, and not PKCS8PrivateKey::BERDecode.


  cout << "Loading verifier key..." << endl;
  FileSource fs2("wtls8-pub.der", true);
  verifier.AccessKey().BERDecode(fs2);


  verifier.GetKey().Validate(prng, 3);
  cout << "Validated verifier key..." << endl;

  cout << "Loading signer key..." << endl;
  FileSource fs1("wtls8-priv.der", true);
  signer.AccessKey().BERDecodePrivateKey(fs1, false, (size_t)fs1.MaxRetrievable());


  signer.GetKey().Validate(prng, 3);
  cout << "Validated signer key..." << endl;

AccessKey() returns a non-const reference; GetKey() returns a const reference.

And you still need the OID patch.

Jeff
...
Reply all
Reply to author
Forward
0 new messages