| /* Copyright 2017 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include <ctype.h> |
| #include <endian.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <getopt.h> |
| #include <openssl/bn.h> |
| #include <openssl/ec.h> |
| #include <openssl/obj_mac.h> |
| #include <openssl/rand.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include "rma_auth.h" |
| #include "curve25519.h" |
| #include "sha256.h" |
| #include "base32.h" |
| |
| #define EC_COORDINATE_SZ 32 |
| #define EC_PRIV_KEY_SZ 32 |
| #define EC_P256_UNCOMPRESSED_PUB_KEY_SZ (EC_COORDINATE_SZ * 2 + 1) |
| #define EC_P256_COMPRESSED_PUB_KEY_SZ (EC_COORDINATE_SZ + 1) |
| |
| #define SERVER_ADDRESS \ |
| "https://www.google.com/chromeos/partner/console/cr50reset/request" |
| |
| /* Test server keys for x25519 and p256 curves. */ |
| static const uint8_t rma_test_server_x25519_public_key[] = { |
| 0x03, 0xae, 0x2d, 0x2c, 0x06, 0x23, 0xe0, 0x73, |
| 0x0d, 0xd3, 0xb7, 0x92, 0xac, 0x54, 0xc5, 0xfd, |
| 0x7e, 0x9c, 0xf0, 0xa8, 0xeb, 0x7e, 0x2a, 0xb5, |
| 0xdb, 0xf4, 0x79, 0x5f, 0x8a, 0x0f, 0x28, 0x3f |
| }; |
| |
| static const uint8_t rma_test_server_x25519_private_key[] = { |
| 0x47, 0x3b, 0xa5, 0xdb, 0xc4, 0xbb, 0xd6, 0x77, |
| 0x20, 0xbd, 0xd8, 0xbd, 0xc8, 0x7a, 0xbb, 0x07, |
| 0x03, 0x79, 0xba, 0x7b, 0x52, 0x8c, 0xec, 0xb3, |
| 0x4d, 0xaa, 0x69, 0xf5, 0x65, 0xb4, 0x31, 0xad |
| }; |
| |
| #define RMA_TEST_SERVER_X25519_KEY_ID 0x10 |
| #define RMA_PROD_SERVER_X25519_KEY_ID 0 |
| |
| /* |
| * P256 curve keys, generated using openssl as follows: |
| * |
| * openssl ecparam -name prime256v1 -genkey -out key.pem |
| * openssl ec -in key.pem -text -noout |
| */ |
| static const uint8_t rma_test_server_p256_private_key[] = { |
| 0x54, 0xb0, 0x82, 0x92, 0x54, 0x92, 0xfc, 0x4a, |
| 0xa7, 0x6b, 0xea, 0x8f, 0x30, 0xcc, 0xf7, 0x3d, |
| 0xa2, 0xf6, 0xa7, 0xad, 0xf0, 0xec, 0x7d, 0xe9, |
| 0x26, 0x75, 0xd1, 0xec, 0xde, 0x20, 0x8f, 0x81 |
| }; |
| |
| /* |
| * P256 public key in full form, x and y coordinates with a single byte |
| * prefix, 65 bytes total. |
| */ |
| static const uint8_t rma_test_server_p256_public_key[] = { |
| 0x04, 0xe7, 0xbe, 0x37, 0xaa, 0x68, 0xca, 0xcc, |
| 0x68, 0xf4, 0x8c, 0x56, 0x65, 0x5a, 0xcb, 0xf8, |
| 0xf4, 0x65, 0x3c, 0xd3, 0xc6, 0x1b, 0xae, 0xd6, |
| 0x51, 0x7a, 0xcc, 0x00, 0x8d, 0x59, 0x6d, 0x1b, |
| 0x0a, 0x66, 0xe8, 0x68, 0x5e, 0x6a, 0x82, 0x19, |
| 0x81, 0x76, 0x84, 0x92, 0x7f, 0x8d, 0xb2, 0xbe, |
| 0xf5, 0x39, 0x50, 0xd5, 0xfe, 0xee, 0x00, 0x67, |
| 0xcf, 0x40, 0x5f, 0x68, 0x12, 0x83, 0x4f, 0xa4, |
| 0x35 |
| }; |
| |
| #define RMA_TEST_SERVER_P256_KEY_ID 0x20 |
| #define RMA_PROD_SERVER_P256_KEY_ID 0x01 |
| |
| /* Default values which can change based on command line arguments. */ |
| static uint8_t server_key_id = RMA_TEST_SERVER_X25519_KEY_ID; |
| static uint8_t board_id[4] = {'Z', 'Z', 'C', 'R'}; |
| static uint8_t device_id[8] = {'T', 'H', 'X', 1, 1, 3, 8, 0xfe}; |
| static uint8_t hw_id[20] = "TESTSAMUS1234"; |
| |
| static char challenge[RMA_CHALLENGE_BUF_SIZE]; |
| static char authcode[RMA_AUTHCODE_BUF_SIZE]; |
| |
| static char *progname; |
| static char *short_opts = "a:b:c:d:hpk:tw:"; |
| static const struct option long_opts[] = { |
| /* name hasarg *flag val */ |
| {"auth_code", 1, NULL, 'a'}, |
| {"board_id", 1, NULL, 'b'}, |
| {"challenge", 1, NULL, 'c'}, |
| {"device_id", 1, NULL, 'd'}, |
| {"help", 0, NULL, 'h'}, |
| {"hw_id", 1, NULL, 'w'}, |
| {"key_id", 1, NULL, 'k'}, |
| {"p256", 0, NULL, 'p'}, |
| {"test", 0, NULL, 't'}, |
| {}, |
| }; |
| |
| void panic_assert_fail(const char *fname, int linenum); |
| void rand_bytes(void *buffer, size_t len); |
| int safe_memcmp(const void *s1, const void *s2, size_t size); |
| |
| void panic_assert_fail(const char *fname, int linenum) |
| { |
| printf("\nASSERTION FAILURE at %s:%d\n", fname, linenum); |
| } |
| |
| int safe_memcmp(const void *s1, const void *s2, size_t size) |
| { |
| const uint8_t *us1 = s1; |
| const uint8_t *us2 = s2; |
| int result = 0; |
| |
| if (size == 0) |
| return 0; |
| |
| while (size--) |
| result |= *us1++ ^ *us2++; |
| |
| return result != 0; |
| } |
| |
| void rand_bytes(void *buffer, size_t len) |
| { |
| RAND_bytes(buffer, len); |
| } |
| |
| /* |
| * Generate a p256 key pair and calculate the shared secret based on our |
| * private key and the server public key. |
| * |
| * Return the X coordinate of the generated public key and the shared secret. |
| * |
| * @pub_key - the compressed public key without the prefix; by convention |
| * between RMA client and server the generated pubic key would |
| * always have prefix of 0x03, (the Y coordinate value is odd), so |
| * it is omitted from the key blob, which allows to keep the blob |
| * size at 32 bytes. |
| * @secret_seed - the product of multiplying of the server point by our |
| * private key, only the 32 bytes of X coordinate are returned. |
| */ |
| static void p256_key_and_secret_seed(uint8_t pub_key[32], |
| uint8_t secret_seed[32]) |
| { |
| const EC_GROUP *group; |
| EC_KEY *key; |
| EC_POINT *pub; |
| EC_POINT *secret_point; |
| uint8_t buf[EC_P256_UNCOMPRESSED_PUB_KEY_SZ]; |
| |
| /* Prepare structures to operate on. */ |
| key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); |
| group = EC_KEY_get0_group(key); |
| pub = EC_POINT_new(group); |
| |
| /* |
| * We might have to try multiple times, until the Y coordinate is an |
| * odd value as required by convention. |
| */ |
| do { |
| EC_KEY_generate_key(key); |
| |
| /* Extract public key into an octal array. */ |
| EC_POINT_point2oct(group, EC_KEY_get0_public_key(key), |
| POINT_CONVERSION_UNCOMPRESSED, |
| buf, sizeof(buf), NULL); |
| |
| /* If Y coordinate is an odd value, we are done. */ |
| } while (!(buf[sizeof(buf) - 1] & 1)); |
| |
| /* Copy X coordinate out. */ |
| memcpy(pub_key, buf + 1, 32); |
| |
| /* |
| * We have our private key and the server's point coordinates (aka |
| * server public key). Let's multiply the coordinates by our private |
| * key to get the shared secret. |
| */ |
| |
| /* Load raw public key into the point structure. */ |
| EC_POINT_oct2point(group, pub, rma_test_server_p256_public_key, |
| sizeof(rma_test_server_p256_public_key), NULL); |
| |
| secret_point = EC_POINT_new(group); |
| |
| /* Multiply server public key by our private key. */ |
| EC_POINT_mul(group, secret_point, 0, pub, |
| EC_KEY_get0_private_key(key), 0); |
| |
| /* Pull the result back into the octal buffer. */ |
| EC_POINT_point2oct(group, secret_point, POINT_CONVERSION_UNCOMPRESSED, |
| buf, sizeof(buf), NULL); |
| |
| /* |
| * Copy X coordinate into the output to use as the shared secret |
| * seed. |
| */ |
| memcpy(secret_seed, buf + 1, 32); |
| |
| /* release resources */ |
| EC_KEY_free(key); |
| EC_POINT_free(pub); |
| EC_POINT_free(secret_point); |
| } |
| |
| /* |
| * When imitating server side, calculate the secret value given the client's |
| * compressed public key (X coordinate only with 0x03 prefix implied) and |
| * knowing our (server) private key. |
| * |
| * @secret - array to return the X coordinate of the calculated point. |
| * @raw_pub_key - X coordinate of the point calculated by the client, 0x03 |
| * prefix implied. |
| */ |
| static void p256_calculate_secret(uint8_t secret[32], |
| const uint8_t raw_pub_key[32]) |
| { |
| uint8_t raw_pub_key_x[EC_P256_COMPRESSED_PUB_KEY_SZ]; |
| EC_KEY *key; |
| const uint8_t *kp = raw_pub_key_x; |
| EC_POINT *secret_point; |
| const EC_GROUP *group; |
| BIGNUM *priv; |
| uint8_t buf[EC_P256_UNCOMPRESSED_PUB_KEY_SZ]; |
| |
| /* Express server private key as a BN. */ |
| priv = BN_new(); |
| BN_bin2bn(rma_test_server_p256_private_key, EC_PRIV_KEY_SZ, priv); |
| |
| /* |
| * Populate a p256 key structure based on the compressed |
| * representation of the client's public key. |
| */ |
| raw_pub_key_x[0] = 3; /* Implied by convention. */ |
| memcpy(raw_pub_key_x + 1, raw_pub_key, sizeof(raw_pub_key_x) - 1); |
| key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); |
| group = EC_KEY_get0_group(key); |
| key = o2i_ECPublicKey(&key, &kp, sizeof(raw_pub_key_x)); |
| |
| /* This is where the multiplication result will go. */ |
| secret_point = EC_POINT_new(group); |
| |
| /* Multiply client's point by our private key. */ |
| EC_POINT_mul(group, secret_point, 0, |
| EC_KEY_get0_public_key(key), |
| priv, 0); |
| |
| /* Pull the result back into the octal buffer. */ |
| EC_POINT_point2oct(group, secret_point, POINT_CONVERSION_UNCOMPRESSED, |
| buf, sizeof(buf), NULL); |
| |
| /* Copy X coordinate into the output to use as the shared secret. */ |
| memcpy(secret, buf + 1, 32); |
| } |
| |
| static int rma_server_side(const char *generated_challenge) |
| { |
| int key_id, version; |
| uint8_t secret[32]; |
| uint8_t hmac[32]; |
| struct rma_challenge c; |
| uint8_t *cptr = (uint8_t *)&c; |
| |
| /* Convert the challenge back into binary */ |
| if (base32_decode(cptr, 8 * sizeof(c), generated_challenge, 9) != |
| 8 * sizeof(c)) { |
| printf("Error decoding challenge\n"); |
| return -1; |
| } |
| |
| version = RMA_CHALLENGE_GET_VERSION(c.version_key_id); |
| key_id = RMA_CHALLENGE_GET_KEY_ID(c.version_key_id); |
| printf("Challenge: %s\n", generated_challenge); |
| printf("Version: %d\n", version); |
| printf("Server KeyID: %d\n", key_id); |
| |
| if (version != RMA_CHALLENGE_VERSION) |
| printf("Unsupported challenge version %d\n", version); |
| |
| /* Calculate the shared secret, use curve based on the key ID. */ |
| switch (key_id) { |
| case RMA_PROD_SERVER_X25519_KEY_ID: |
| printf("Unsupported Prod KeyID %d\n", key_id); |
| case RMA_TEST_SERVER_X25519_KEY_ID: |
| X25519(secret, rma_test_server_x25519_private_key, |
| c.device_pub_key); |
| break; |
| case RMA_PROD_SERVER_P256_KEY_ID: |
| printf("Unsupported Prod KeyID %d\n", key_id); |
| case RMA_TEST_SERVER_P256_KEY_ID: |
| p256_calculate_secret(secret, c.device_pub_key); |
| break; |
| default: |
| printf("Unknown KeyID %d\n", key_id); |
| return 1; |
| } |
| |
| /* |
| * Auth code is a truncated HMAC of the ephemeral public key, BoardID, |
| * and DeviceID. |
| */ |
| hmac_SHA256(hmac, secret, sizeof(secret), cptr + 1, sizeof(c) - 1); |
| if (base32_encode(authcode, RMA_AUTHCODE_BUF_SIZE, |
| hmac, RMA_AUTHCODE_CHARS * 5, 0)) { |
| printf("Error encoding auth code\n"); |
| return -1; |
| } |
| printf("Authcode: %s\n", authcode); |
| |
| return 0; |
| }; |
| |
| static int rma_create_test_challenge(int p256_mode) |
| { |
| uint8_t temp[32]; /* Private key or HMAC */ |
| uint8_t secret_seed[32]; |
| struct rma_challenge c; |
| uint8_t *cptr = (uint8_t *)&c; |
| uint32_t bid; |
| |
| /* Clear the current challenge and authcode, if any */ |
| memset(challenge, 0, sizeof(challenge)); |
| memset(authcode, 0, sizeof(authcode)); |
| |
| memset(&c, 0, sizeof(c)); |
| c.version_key_id = RMA_CHALLENGE_VKID_BYTE( |
| RMA_CHALLENGE_VERSION, server_key_id); |
| |
| memcpy(&bid, board_id, sizeof(bid)); |
| bid = be32toh(bid); |
| memcpy(c.board_id, &bid, sizeof(c.board_id)); |
| |
| memcpy(c.device_id, device_id, sizeof(c.device_id)); |
| |
| if (p256_mode) { |
| p256_key_and_secret_seed(c.device_pub_key, secret_seed); |
| } else { |
| /* Calculate a new ephemeral key pair */ |
| X25519_keypair(c.device_pub_key, temp); |
| /* Calculate the shared secret seed. */ |
| X25519(secret_seed, temp, rma_test_server_x25519_public_key); |
| } |
| |
| /* Encode the challenge */ |
| if (base32_encode(challenge, sizeof(challenge), cptr, 8 * sizeof(c), 9)) |
| return 1; |
| |
| /* |
| * Auth code is a truncated HMAC of the ephemeral public key, BoardID, |
| * and DeviceID. Those are all in the right order in the challenge |
| * struct, after the version/key id byte. |
| */ |
| hmac_SHA256(temp, secret_seed, sizeof(secret_seed), |
| cptr + 1, sizeof(c) - 1); |
| if (base32_encode(authcode, sizeof(authcode), temp, |
| RMA_AUTHCODE_CHARS * 5, 0)) |
| return 1; |
| |
| return 0; |
| } |
| |
| int rma_try_authcode(const char *code) |
| { |
| return safe_memcmp(authcode, code, RMA_AUTHCODE_CHARS); |
| } |
| |
| static void dump_key(const char *title, const uint8_t *key, size_t key_size) |
| { |
| size_t i; |
| const int bytes_per_line = 8; |
| |
| printf("\n\n\%s\n", title); |
| for (i = 0; i < key_size; i++) |
| printf("%02x%c", key[i], ((i + 1) % bytes_per_line) ? ' ':'\n'); |
| |
| if (i % bytes_per_line) |
| printf("\n"); |
| } |
| |
| static void print_params(int p_flag) |
| { |
| int i; |
| const uint8_t *priv_key; |
| const uint8_t *pub_key; |
| int key_id; |
| size_t pub_key_size; |
| |
| printf("\nBoard Id:\n"); |
| for (i = 0; i < 4; i++) |
| printf("%c ", board_id[i]); |
| |
| printf("\n\nDevice Id:\n"); |
| for (i = 0; i < 3; i++) |
| printf("%c ", device_id[i]); |
| for (i = 3; i < 8; i++) |
| printf("%02x ", device_id[i]); |
| |
| if (p_flag) { |
| priv_key = rma_test_server_p256_private_key; |
| pub_key = rma_test_server_p256_public_key; |
| pub_key_size = sizeof(rma_test_server_p256_public_key); |
| key_id = RMA_TEST_SERVER_P256_KEY_ID; |
| } else { |
| priv_key = rma_test_server_x25519_private_key; |
| pub_key = rma_test_server_x25519_public_key; |
| pub_key_size = sizeof(rma_test_server_x25519_public_key); |
| key_id = RMA_TEST_SERVER_X25519_KEY_ID; |
| } |
| |
| printf("\n\nServer Key Id:\n"); |
| printf("%02x", key_id); |
| |
| /* Both private keys are of the same size */ |
| dump_key("Server Private Key:", priv_key, EC_PRIV_KEY_SZ); |
| dump_key("Server Public Key:", pub_key, pub_key_size); |
| |
| printf("\nChallenge:\n"); |
| for (i = 0; i < RMA_CHALLENGE_CHARS; i++) { |
| printf("%c", challenge[i]); |
| if (((i + 1) % 5) == 0) |
| printf(" "); |
| if (((i + 1) % 40) == 0) |
| printf("\n"); |
| } |
| |
| printf("\nAuthorization Code:\n"); |
| for (i = 0; i < RMA_AUTHCODE_BUF_SIZE; i++) |
| printf("%c", authcode[i]); |
| |
| printf("\n\nChallenge String:\n"); |
| printf("%s?challenge=", SERVER_ADDRESS); |
| for (i = 0; i < RMA_CHALLENGE_CHARS; i++) |
| printf("%c", challenge[i]); |
| printf("&hwid=%s\n", hw_id); |
| |
| printf("\n"); |
| } |
| |
| static void usage(void) |
| { |
| printf("\nUsage: %s [--p256] --key_id <arg> --board_id <arg> " |
| "--device_id <arg> --hw_id <arg> |\n" |
| " --auth_code <arg> |\n" |
| " --challenge <arg>\n" |
| "\n" |
| "This is used to generate the cr50 or server responses for rma " |
| "open.\n" |
| "The cr50 side can be used to generate a challenge response " |
| "and sends authoriztion code to reset device.\n" |
| "The server side can generate an authcode from cr50's " |
| "rma challenge.\n" |
| "\n" |
| " -c,--challenge The challenge generated by cr50\n" |
| " -k,--key_id Index of the server private key\n" |
| " -b,--board_id BoardID type field\n" |
| " -d,--device_id Device-unique identifier\n" |
| " -a,--auth_code Reset authorization code\n" |
| " -w,--hw_id Hardware id\n" |
| " -h,--help Show this message\n" |
| " -p,--p256 Use prime256v1 curve instead of x25519\n" |
| " -t,--test " |
| "Generate challenge using default test inputs\n" |
| "\n", progname); |
| } |
| |
| static int atoh(char *v) |
| { |
| char hn; |
| char ln; |
| |
| hn = toupper(*v); |
| ln = toupper(*(v + 1)); |
| |
| hn -= (isdigit(hn) ? '0' : '7'); |
| ln -= (isdigit(ln) ? '0' : '7'); |
| |
| if ((hn < 0 || hn > 0xf) || (ln < 0 || ln > 0xf)) |
| return 0; |
| |
| return (hn << 4) | ln; |
| } |
| |
| static int set_server_key_id(char *id) |
| { |
| /* verify length */ |
| if (strlen(id) != 2) |
| return 1; |
| |
| /* verify digits */ |
| if (!isxdigit(*id) || !isxdigit(*(id+1))) |
| return 1; |
| |
| server_key_id = atoh(id); |
| |
| return 0; |
| } |
| |
| static int set_board_id(char *id) |
| { |
| int i; |
| |
| /* verify length */ |
| if (strlen(id) != 8) |
| return 1; |
| |
| /* verify digits */ |
| for (i = 0; i < 8; i++) |
| if (!isxdigit(*(id + i))) |
| return 1; |
| |
| for (i = 0; i < 4; i++) |
| board_id[i] = atoh((id + (i*2))); |
| |
| return 0; |
| } |
| |
| static int set_device_id(char *id) |
| { |
| int i; |
| |
| /* verify length */ |
| if (strlen(id) != 16) |
| return 1; |
| |
| for (i = 0; i < 16; i++) |
| if (!isxdigit(*(id + i))) |
| return 1; |
| |
| for (i = 0; i < 8; i++) |
| device_id[i] = atoh((id + (i*2))); |
| |
| return 0; |
| } |
| |
| static int set_hw_id(char *id) |
| { |
| int i; |
| int len; |
| |
| len = strlen(id); |
| if (len > 20) |
| len = 20; |
| |
| for (i = 0; i < 20; i++) |
| hw_id[i] = *(id + i); |
| |
| return 0; |
| } |
| |
| static int set_auth_code(char *code) |
| { |
| int i; |
| |
| if (strlen(code) != 8) |
| return 1; |
| |
| for (i = 0; i < 8; i++) |
| authcode[i] = *(code + i); |
| authcode[i] = 0; |
| |
| return 0; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| int a_flag = 0; |
| int b_flag = 0; |
| int d_flag = 0; |
| int k_flag = 0; |
| int p_flag = 0; |
| int t_flag = 0; |
| int w_flag = 0; |
| int i; |
| |
| progname = strrchr(argv[0], '/'); |
| if (progname) |
| progname++; |
| else |
| progname = argv[0]; |
| |
| opterr = 0; |
| while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) { |
| switch (i) { |
| case 't': |
| t_flag = 1; |
| break; |
| case 'c': |
| return rma_server_side(optarg); |
| case 'k': |
| if (set_server_key_id(optarg)) { |
| printf("Malformed key id\n"); |
| return 1; |
| } |
| k_flag = 1; |
| break; |
| case 'b': |
| if (set_board_id(optarg)) { |
| printf("Malformed board id\n"); |
| return 1; |
| } |
| b_flag = 1; |
| break; |
| case 'd': |
| if (set_device_id(optarg)) { |
| printf("Malformed device id\n"); |
| return 1; |
| } |
| d_flag = 1; |
| break; |
| case 'a': |
| if (set_auth_code(optarg)) { |
| printf("Malformed authorization code\n"); |
| return 1; |
| } |
| a_flag = 1; |
| break; |
| case 'w': |
| if (set_hw_id(optarg)) { |
| printf("Malformed hardware id\n"); |
| return 1; |
| } |
| w_flag = 1; |
| break; |
| case 'h': |
| usage(); |
| return 0; |
| case 0: /* auto-handled option */ |
| break; |
| case '?': |
| if (optopt) |
| printf("Unrecognized option: -%c\n", optopt); |
| else |
| printf("Unrecognized option: %s\n", |
| argv[optind - 1]); |
| break; |
| case ':': |
| printf("Missing argument to %s\n", argv[optind - 1]); |
| break; |
| case 'p': |
| p_flag = 1; |
| server_key_id = RMA_TEST_SERVER_P256_KEY_ID; |
| break; |
| default: |
| printf("Internal error at %s:%d\n", __FILE__, __LINE__); |
| return 1; |
| } |
| } |
| |
| if (a_flag) { |
| FILE *acode; |
| char verify_authcode[RMA_AUTHCODE_BUF_SIZE]; |
| int rv; |
| |
| acode = fopen("/tmp/authcode", "r"); |
| if (acode == NULL) { |
| printf("Please generate challenge\n"); |
| return 1; |
| } |
| |
| rv = fread(verify_authcode, 1, RMA_AUTHCODE_BUF_SIZE, acode); |
| if (rv != RMA_AUTHCODE_BUF_SIZE) { |
| printf("Error reading saved authcode\n"); |
| return 1; |
| } |
| if (strcmp(verify_authcode, authcode) == 0) |
| printf("Code Accepted\n"); |
| else |
| printf("Invalid Code\n"); |
| |
| } else { |
| if (!t_flag) { /* Use default values */ |
| if (!k_flag || !b_flag || !d_flag || !w_flag) { |
| printf("server-side: Flag -c is mandatory\n"); |
| printf("cr50-side: Flags -k, -b, -d, and -w " |
| "are mandatory\n"); |
| return 1; |
| } |
| } |
| |
| rma_create_test_challenge(p_flag); |
| |
| { |
| FILE *acode; |
| |
| acode = fopen("/tmp/authcode", "w"); |
| if (acode < 0) |
| return 1; |
| fwrite(authcode, 1, RMA_AUTHCODE_BUF_SIZE, acode); |
| fclose(acode); |
| } |
| |
| print_params(p_flag); |
| } |
| |
| return 0; |
| } |