diff --git a/certs/client-ecc-cert.pem b/certs/client-ecc-cert.pem new file mode 100644 index 000000000..4d0448fc4 --- /dev/null +++ b/certs/client-ecc-cert.pem @@ -0,0 +1,54 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + bf:cc:cb:7a:0a:07:42:82 + Signature Algorithm: ecdsa-with-SHA1 + Issuer: C=US, ST=Oregon, L=Salem, O=Client ECC, OU=Fast, CN=www.yassl.com/emailAddress=info@yassl.com + Validity + Not Before: May 1 23:51:33 2012 GMT + Not After : Jan 26 23:51:33 2015 GMT + Subject: C=US, ST=Oregon, L=Salem, O=Client ECC, OU=Fast, CN=www.yassl.com/emailAddress=info@yassl.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + EC Public Key: + pub: + 04:55:bf:f4:0f:44:50:9a:3d:ce:9b:b7:f0:c5:4d: + f5:70:7b:d4:ec:24:8e:19:80:ec:5a:4c:a2:24:03: + 62:2c:9b:da:ef:a2:35:12:43:84:76:16:c6:56:95: + 06:cc:01:a9:bd:f6:75:1a:42:f7:bd:a9:b2:36:22: + 5f:c7:5d:7f:b4 + ASN1 OID: prime256v1 + X509v3 extensions: + X509v3 Subject Key Identifier: + EB:D4:4B:59:6B:95:61:3F:51:57:B6:04:4D:89:41:88:44:5C:AB:F2 + X509v3 Authority Key Identifier: + keyid:EB:D4:4B:59:6B:95:61:3F:51:57:B6:04:4D:89:41:88:44:5C:AB:F2 + DirName:/C=US/ST=Oregon/L=Salem/O=Client ECC/OU=Fast/CN=www.yassl.com/emailAddress=info@yassl.com + serial:BF:CC:CB:7A:0A:07:42:82 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: ecdsa-with-SHA1 + 30:44:02:20:26:08:44:95:35:2e:fa:9d:20:01:a6:79:60:ed: + 35:a7:0a:dd:7a:0e:75:c5:80:d2:0b:9f:6a:90:d6:31:76:75: + 02:20:2d:87:a2:bb:d5:e2:42:61:35:19:59:40:1d:fd:71:4f: + 28:65:96:99:e6:85:1b:09:ad:d4:58:71:56:63:0b:c7 +-----BEGIN CERTIFICATE----- +MIIC+jCCAqKgAwIBAgIJAL/My3oKB0KCMAkGByqGSM49BAEwgYkxCzAJBgNVBAYT +AlVTMQ8wDQYDVQQIEwZPcmVnb24xDjAMBgNVBAcTBVNhbGVtMRMwEQYDVQQKEwpD +bGllbnQgRUNDMQ0wCwYDVQQLEwRGYXN0MRYwFAYDVQQDEw13d3cueWFzc2wuY29t +MR0wGwYJKoZIhvcNAQkBFg5pbmZvQHlhc3NsLmNvbTAeFw0xMjA1MDEyMzUxMzNa +Fw0xNTAxMjYyMzUxMzNaMIGJMQswCQYDVQQGEwJVUzEPMA0GA1UECBMGT3JlZ29u +MQ4wDAYDVQQHEwVTYWxlbTETMBEGA1UEChMKQ2xpZW50IEVDQzENMAsGA1UECxME +RmFzdDEWMBQGA1UEAxMNd3d3Lnlhc3NsLmNvbTEdMBsGCSqGSIb3DQEJARYOaW5m +b0B5YXNzbC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARVv/QPRFCaPc6b +t/DFTfVwe9TsJI4ZgOxaTKIkA2Ism9rvojUSQ4R2FsZWlQbMAam99nUaQve9qbI2 +Il/HXX+0o4HxMIHuMB0GA1UdDgQWBBTr1EtZa5VhP1FXtgRNiUGIRFyr8jCBvgYD +VR0jBIG2MIGzgBTr1EtZa5VhP1FXtgRNiUGIRFyr8qGBj6SBjDCBiTELMAkGA1UE +BhMCVVMxDzANBgNVBAgTBk9yZWdvbjEOMAwGA1UEBxMFU2FsZW0xEzARBgNVBAoT +CkNsaWVudCBFQ0MxDTALBgNVBAsTBEZhc3QxFjAUBgNVBAMTDXd3dy55YXNzbC5j +b20xHTAbBgkqhkiG9w0BCQEWDmluZm9AeWFzc2wuY29tggkAv8zLegoHQoIwDAYD +VR0TBAUwAwEB/zAJBgcqhkjOPQQBA0cAMEQCICYIRJU1LvqdIAGmeWDtNacK3XoO +dcWA0gufapDWMXZ1AiAth6K71eJCYTUZWUAd/XFPKGWWmeaFGwmt1FhxVmMLxw== +-----END CERTIFICATE----- diff --git a/certs/ecc-client-key.pem b/certs/ecc-client-key.pem new file mode 100644 index 000000000..cf9812d80 --- /dev/null +++ b/certs/ecc-client-key.pem @@ -0,0 +1,9 @@ +ASN1 OID: prime256v1 +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIPjPkmu9HijxqKuhI08ydBiIUK1+x+yS+I+XTa9WiWXHoAoGCCqGSM49 +AwEHoUQDQgAEVb/0D0RQmj3Om7fwxU31cHvU7CSOGYDsWkyiJANiLJva76I1EkOE +dhbGVpUGzAGpvfZ1GkL3vamyNiJfx11/tA== +-----END EC PRIVATE KEY----- diff --git a/cyassl/test.h b/cyassl/test.h index fbc0852c4..57986f835 100644 --- a/cyassl/test.h +++ b/cyassl/test.h @@ -107,6 +107,8 @@ static const char* cliKey = "./certs/client-key.pem"; static const char* ntruCert = "./certs/ntru-cert.pem"; static const char* ntruKey = "./certs/ntru-key.raw"; static const char* dhParam = "./certs/dh2048.pem"; +static const char* cliEccKey = "./certs/ecc-client-key.pem"; +static const char* cliEccCert = "./certs/client-ecc-cert.pem"; typedef struct tcp_ready { int ready; /* predicate */ diff --git a/examples/client/client.c b/examples/client/client.c index 39f9cd1d9..0f2b72bbd 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -146,6 +146,17 @@ void client_test(void* args) /* ./client // plain mode */ /* for client cert authentication if server requests */ #ifndef NO_FILESYSTEM + #ifdef HAVE_ECC + if (CyaSSL_CTX_use_certificate_file(ctx, cliEccCert, SSL_FILETYPE_PEM) + != SSL_SUCCESS) + err_sys("can't load ecc client cert file, " + "Please run from CyaSSL home dir"); + + if (CyaSSL_CTX_use_PrivateKey_file(ctx, cliEccKey, SSL_FILETYPE_PEM) + != SSL_SUCCESS) + err_sys("can't load ecc client key file, " + "Please run from CyaSSL home dir"); + #else if (CyaSSL_CTX_use_certificate_file(ctx, cliCert, SSL_FILETYPE_PEM) != SSL_SUCCESS) err_sys("can't load client cert file, " @@ -155,6 +166,7 @@ void client_test(void* args) != SSL_SUCCESS) err_sys("can't load client key file, " "Please run from CyaSSL home dir"); + #endif /* HAVE_ECC */ #else load_buffer(ctx, cliCert, CYASSL_CERT); load_buffer(ctx, cliKey, CYASSL_KEY); diff --git a/examples/server/server.c b/examples/server/server.c index f6a34f3ea..c7fe1f965 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -115,6 +115,10 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) != SSL_SUCCESS) err_sys("can't load server ecc key file, " "Please run from CyaSSL home dir"); + /* for client auth */ + if (SSL_CTX_load_verify_locations(ctx, cliEccCert, 0) != SSL_SUCCESS) + err_sys("can't load ecc ca file, Please run from CyaSSL home dir"); + #elif HAVE_NTRU if (SSL_CTX_use_certificate_file(ctx, ntruCert, SSL_FILETYPE_PEM) != SSL_SUCCESS) diff --git a/src/internal.c b/src/internal.c index 3dc5d592e..929b3687f 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4552,7 +4552,12 @@ int SetCipherList(Suites* s, const char* list) byte *output; int sendSz = 0, length, ret; word32 idx = 0; + word32 sigOutSz = 0; RsaKey key; + int usingEcc = 0; +#ifdef HAVE_ECC + ecc_key eccKey; +#endif if (ssl->options.sendVerify == SEND_BLANK_CERT) return 0; /* sent blank cert, can't verify */ @@ -4567,10 +4572,31 @@ int SetCipherList(Suites* s, const char* list) BuildCertHashes(ssl, &ssl->certHashes); - /* TODO: when add DSS support check here */ +#ifdef HAVE_ECC + ecc_init(&eccKey); +#endif InitRsaKey(&key, ssl->heap); ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key, - ssl->buffers.key.length); + ssl->buffers.key.length); + if (ret == 0) + sigOutSz = RsaEncryptSize(&key); + else { + #ifdef HAVE_ECC + CYASSL_MSG("Trying ECC client cert, RSA didn't work"); + + idx = 0; + ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &eccKey, + ssl->buffers.key.length); + if (ret == 0) { + CYASSL_MSG("Using ECC client cert"); + usingEcc = 1; + sigOutSz = ecc_sig_size(&eccKey); + } + else { + CYASSL_MSG("Bad client cert type"); + } + #endif + } if (ret == 0) { byte* verify = (byte*)&output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ]; @@ -4583,34 +4609,45 @@ int SetCipherList(Suites* s, const char* list) if (ssl->options.dtls) verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; #endif - length = RsaEncryptSize(&key); + length = sigOutSz; if (IsAtLeastTLSv1_2(ssl)) { verify[0] = sha_mac; - verify[1] = rsa_sa_algo; + verify[1] = usingEcc ? ecc_dsa_sa_algo : rsa_sa_algo; extraSz = HASH_SIG_SIZE; } c16toa((word16)length, verify + extraSz); /* prepend verify header*/ - if (IsAtLeastTLSv1_2(ssl)) { - byte* digest; - int typeH; - int digestSz; - - /* sha1 for now */ - digest = ssl->certHashes.sha; - typeH = SHAh; - digestSz = SHA_DIGEST_SIZE; - - signSz = EncodeSignature(encodedSig, digest, digestSz, typeH); - signBuffer = encodedSig; + if (usingEcc) { +#ifdef HAVE_ECC + word32 localSz = sigOutSz; + ret = ecc_sign_hash(signBuffer + MD5_DIGEST_SIZE, + SHA_DIGEST_SIZE, verify + extraSz + VERIFY_HEADER, + &localSz, &ssl->rng, &eccKey); +#endif } + else { + if (IsAtLeastTLSv1_2(ssl)) { + byte* digest; + int typeH; + int digestSz; - ret = RsaSSL_Sign(signBuffer, signSz, verify + extraSz + - VERIFY_HEADER, ENCRYPT_LEN, &key, &ssl->rng); + /* sha1 for now */ + digest = ssl->certHashes.sha; + typeH = SHAh; + digestSz = SHA_DIGEST_SIZE; - if (ret > 0) { - ret = 0; /* reset */ + signSz = EncodeSignature(encodedSig, digest,digestSz,typeH); + signBuffer = encodedSig; + } + ret = RsaSSL_Sign(signBuffer, signSz, verify + extraSz + + VERIFY_HEADER, ENCRYPT_LEN, &key, &ssl->rng); + + if (ret > 0) + ret = 0; /* RSA reset */ + } + + if (ret == 0) { AddHeaders(output, length + extraSz + VERIFY_HEADER, certificate_verify, ssl); @@ -4625,6 +4662,9 @@ int SetCipherList(Suites* s, const char* list) } FreeRsaKey(&key); +#ifdef HAVE_ECC + ecc_free(&eccKey); +#endif if (ret == 0) { #ifdef CYASSL_CALLBACKS @@ -5548,8 +5588,11 @@ int SetCipherList(Suites* s, const char* list) sig = &input[i]; *inOutsz = i + sz; - /* TODO: when add DSS support check here */ + + /* RSA */ if (ssl->peerRsaKeyPresent != 0) { + CYASSL_MSG("Doing RSA peer cert verify"); + outLen = RsaSSL_VerifyInline(sig, sz, &out, &ssl->peerRsaKey); if (IsAtLeastTLSv1_2(ssl)) { @@ -5567,14 +5610,28 @@ int SetCipherList(Suites* s, const char* list) sigSz = EncodeSignature(encodedSig, digest, digestSz, typeH); if (outLen == (int)sigSz && XMEMCMP(out, encodedSig,sigSz) == 0) - ret = 0; + ret = 0; /* verified */ } else { if (outLen == sizeof(ssl->certHashes) && XMEMCMP(out, ssl->certHashes.md5, sizeof(ssl->certHashes)) == 0) - ret = 0; + ret = 0; /* verified */ } } +#ifdef HAVE_ECC + else if (ssl->peerEccDsaKeyPresent) { + int verify = 0; + int err = -1; + + CYASSL_MSG("Doing ECC peer cert verify"); + + err = ecc_verify_hash(sig, sz, ssl->certHashes.sha, SHA_DIGEST_SIZE, + &verify, &ssl->peerEccDsaKey); + + if (err == 0 && verify == 1) + ret = 0; /* verified */ + } +#endif return ret; }