Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
fido-u2f/fido-example.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
163 lines (142 sloc)
6.07 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* ============= | |
| * FIDO U2F Test | |
| * ============= | |
| * Specs: http://fidoalliance.org/specs/fido-u2f-v1.0-ps-20141009/fido-u2f-raw-message-formats-ps-20141009.html | |
| * Compile: gcc -Wall -Werror -g -o fido-example fido-example.c -lssl */ | |
| /* PC-Lint options */ | |
| /*lint -efile(537, openssl/ecdsa.h, openssl/sha.h) / no include guard present */ | |
| /*lint -e793 / ANSI/ISO limit of 31 'significant characters... */ | |
| /*lint -e801 / Use of goto is deprecated */ | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <sysexits.h> | |
| #include <openssl/x509.h> | |
| #include <openssl/ecdsa.h> | |
| #include <openssl/sha.h> | |
| #include <openssl/err.h> | |
| static const unsigned char const registrationData[] = { | |
| 0x05,0x04,0xb1,0x74,0xbc,0x49,0xc7,0xca,0x25,0x4b,0x70,0xd2,0xe5,0xc2,0x07,0xce, | |
| 0xe9,0xcf,0x17,0x48,0x20,0xeb,0xd7,0x7e,0xa3,0xc6,0x55,0x08,0xc2,0x6d,0xa5,0x1b, | |
| 0x65,0x7c,0x1c,0xc6,0xb9,0x52,0xf8,0x62,0x16,0x97,0x93,0x64,0x82,0xda,0x0a,0x6d, | |
| 0x3d,0x38,0x26,0xa5,0x90,0x95,0xda,0xf6,0xcd,0x7c,0x03,0xe2,0xe6,0x03,0x85,0xd2, | |
| 0xf6,0xd9,0x40,0x2a,0x55,0x2d,0xfd,0xb7,0x47,0x7e,0xd6,0x5f,0xd8,0x41,0x33,0xf8, | |
| 0x61,0x96,0x01,0x0b,0x22,0x15,0xb5,0x7d,0xa7,0x5d,0x31,0x5b,0x7b,0x9e,0x8f,0xe2, | |
| 0xe3,0x92,0x5a,0x60,0x19,0x55,0x1b,0xab,0x61,0xd1,0x65,0x91,0x65,0x9c,0xba,0xf0, | |
| 0x0b,0x49,0x50,0xf7,0xab,0xfe,0x66,0x60,0xe2,0xe0,0x06,0xf7,0x68,0x68,0xb7,0x72, | |
| 0xd7,0x0c,0x25,0x30,0x82,0x01,0x3c,0x30,0x81,0xe4,0xa0,0x03,0x02,0x01,0x02,0x02, | |
| 0x0a,0x47,0x90,0x12,0x80,0x00,0x11,0x55,0x95,0x73,0x52,0x30,0x0a,0x06,0x08,0x2a, | |
| 0x86,0x48,0xce,0x3d,0x04,0x03,0x02,0x30,0x17,0x31,0x15,0x30,0x13,0x06,0x03,0x55, | |
| 0x04,0x03,0x13,0x0c,0x47,0x6e,0x75,0x62,0x62,0x79,0x20,0x50,0x69,0x6c,0x6f,0x74, | |
| 0x30,0x1e,0x17,0x0d,0x31,0x32,0x30,0x38,0x31,0x34,0x31,0x38,0x32,0x39,0x33,0x32, | |
| 0x5a,0x17,0x0d,0x31,0x33,0x30,0x38,0x31,0x34,0x31,0x38,0x32,0x39,0x33,0x32,0x5a, | |
| 0x30,0x31,0x31,0x2f,0x30,0x2d,0x06,0x03,0x55,0x04,0x03,0x13,0x26,0x50,0x69,0x6c, | |
| 0x6f,0x74,0x47,0x6e,0x75,0x62,0x62,0x79,0x2d,0x30,0x2e,0x34,0x2e,0x31,0x2d,0x34, | |
| 0x37,0x39,0x30,0x31,0x32,0x38,0x30,0x30,0x30,0x31,0x31,0x35,0x35,0x39,0x35,0x37, | |
| 0x33,0x35,0x32,0x30,0x59,0x30,0x13,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,0x01, | |
| 0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,0x42,0x00,0x04,0x8d,0x61, | |
| 0x7e,0x65,0xc9,0x50,0x8e,0x64,0xbc,0xc5,0x67,0x3a,0xc8,0x2a,0x67,0x99,0xda,0x3c, | |
| 0x14,0x46,0x68,0x2c,0x25,0x8c,0x46,0x3f,0xff,0xdf,0x58,0xdf,0xd2,0xfa,0x3e,0x6c, | |
| 0x37,0x8b,0x53,0xd7,0x95,0xc4,0xa4,0xdf,0xfb,0x41,0x99,0xed,0xd7,0x86,0x2f,0x23, | |
| 0xab,0xaf,0x02,0x03,0xb4,0xb8,0x91,0x1b,0xa0,0x56,0x99,0x94,0xe1,0x01,0x30,0x0a, | |
| 0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x02,0x03,0x47,0x00,0x30,0x44,0x02, | |
| 0x20,0x60,0xcd,0xb6,0x06,0x1e,0x9c,0x22,0x26,0x2d,0x1a,0xac,0x1d,0x96,0xd8,0xc7, | |
| 0x08,0x29,0xb2,0x36,0x65,0x31,0xdd,0xa2,0x68,0x83,0x2c,0xb8,0x36,0xbc,0xd3,0x0d, | |
| 0xfa,0x02,0x20,0x63,0x1b,0x14,0x59,0xf0,0x9e,0x63,0x30,0x05,0x57,0x22,0xc8,0xd8, | |
| 0x9b,0x7f,0x48,0x88,0x3b,0x90,0x89,0xb8,0x8d,0x60,0xd1,0xd9,0x79,0x59,0x02,0xb3, | |
| 0x04,0x10,0xdf,0x30,0x45,0x02,0x20,0x14,0x71,0x89,0x9b,0xcc,0x39,0x87,0xe6,0x2e, | |
| 0x82,0x02,0xc9,0xb3,0x9c,0x33,0xc1,0x90,0x33,0xf7,0x34,0x03,0x52,0xdb,0xa8,0x0f, | |
| 0xca,0xb0,0x17,0xdb,0x92,0x30,0xe4,0x02,0x21,0x00,0x82,0x67,0x7d,0x67,0x3d,0x89, | |
| 0x19,0x33,0xad,0xe6,0xf6,0x17,0xe5,0xdb,0xde,0x2e,0x24,0x7e,0x70,0x42,0x3f,0xd5, | |
| 0xad,0x78,0x04,0xa6,0xd3,0xd3,0x96,0x1e,0xf8,0x71 }; | |
| static const char* const appId = "http://example.com"; | |
| static const char* const clientData = | |
| "{\"typ\":\"navigator.id.finishEnrollment\"," | |
| "\"challenge\":\"vqrS6WXDe1JUs5_c3i4-LkKIHRr-3XVb3azuA5TifHo\"," | |
| "\"cid_pubkey\":{" | |
| "\"kty\":\"EC\"," | |
| "\"crv\":\"P-256\"," | |
| "\"x\":\"HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8\"," | |
| "\"y\":\"XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4\"" | |
| "}," | |
| "\"origin\":\"http://example.com\"" | |
| "}"; | |
| int main(int argc, char * const argv[]) { | |
| int ret = EX_DATAERR; | |
| ssize_t cd_len, reg_len; | |
| unsigned char kh_len; | |
| unsigned const char *kh, *sig; | |
| size_t siglen; | |
| EVP_PKEY *pkey = NULL; | |
| unsigned char cp_hash[SHA256_DIGEST_LENGTH]; | |
| unsigned char ap_hash[SHA256_DIGEST_LENGTH]; | |
| EVP_MD_CTX ctx; | |
| X509 *crt = NULL; | |
| unsigned const char *ptr; | |
| int i; | |
| cd_len = strlen(clientData); | |
| reg_len = sizeof(registrationData); | |
| if (registrationData[0] != 0x05) { | |
| fprintf(stderr, "invalid header byte\n"); | |
| goto DONE; | |
| } | |
| /* key handle */ | |
| kh = registrationData+67; | |
| kh_len = registrationData[66]; | |
| /* parse attestation certificate (X.509) */ | |
| ptr = registrationData + 67 + kh_len; | |
| crt = d2i_X509(NULL, (const unsigned char**)&ptr, reg_len - (ptr-registrationData)); | |
| if (crt == NULL) { | |
| fprintf(stderr, "Error while parsing X509\n"); | |
| goto DONE; | |
| } | |
| /* check if this is a valid signature */ | |
| sig = ptr; | |
| ECDSA_SIG *ecsig = d2i_ECDSA_SIG(NULL, (const unsigned char**)&ptr, reg_len - (ptr-registrationData)); | |
| if (ecsig == NULL) { | |
| fprintf(stderr, "Error while reading signature\n"); | |
| ECDSA_SIG_free(ecsig); | |
| ecsig = NULL; | |
| goto DONE; | |
| } | |
| siglen = ptr-sig; | |
| ECDSA_SIG_free(ecsig); | |
| ecsig = NULL; | |
| /* extract public key from X509 attestation certificare */ | |
| pkey = X509_get_pubkey(crt); | |
| if (pkey == NULL) { | |
| fprintf(stderr, "Can't get public key!\n"); | |
| goto DONE; | |
| } | |
| /* generate SHA256 hash on challenge parameter and application parameter */ | |
| (void)SHA256((const unsigned char*)clientData, cd_len, cp_hash); | |
| (void)SHA256((const unsigned char*)appId, strlen(appId), ap_hash); | |
| /* verify signature */ | |
| if (EVP_VerifyInit(&ctx, EVP_sha256()) != 1) { | |
| fprintf(stderr, "EVP_VerifyInit() failed\n"); | |
| goto DONE; | |
| } | |
| (void)EVP_VerifyUpdate(&ctx, "\0", 1UL); | |
| (void)EVP_VerifyUpdate(&ctx, ap_hash, 32UL); | |
| (void)EVP_VerifyUpdate(&ctx, cp_hash, 32UL); | |
| (void)EVP_VerifyUpdate(&ctx, kh, (unsigned long)kh_len); | |
| (void)EVP_VerifyUpdate(&ctx, registrationData+1, 65UL); | |
| if ((i = EVP_VerifyFinal(&ctx, sig, siglen, pkey)) != 1) { | |
| fprintf(stderr, "EVP_VerifyFinal failed: err=%i, %s\n", i, ERR_error_string(ERR_get_error(), NULL)); | |
| (void)EVP_MD_CTX_cleanup(&ctx); | |
| goto DONE; | |
| } | |
| (void)EVP_MD_CTX_cleanup(&ctx); | |
| printf("Valid response.\n"); | |
| ret = EX_OK; | |
| DONE: | |
| if (crt != NULL) { | |
| X509_free(crt); | |
| crt = NULL; | |
| } | |
| if (pkey != NULL) { | |
| EVP_PKEY_free(pkey); | |
| pkey = NULL; | |
| } | |
| return(ret); | |
| } |