Skip to content
This repository has been archived by the owner on Aug 10, 2023. It is now read-only.

Commit

Permalink
- Add logic to display NEO address on device when requesting a public…
Browse files Browse the repository at this point in the history
… key

- Restore base58 code from boilerplate app
  • Loading branch information
ixje committed Aug 11, 2021
1 parent 52d4725 commit f9735aa
Show file tree
Hide file tree
Showing 19 changed files with 494 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/apdu/dispatcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ int apdu_dispatcher(const command_t *cmd) {

return handler_get_app_name();
case GET_PUBLIC_KEY:
if (cmd->p1 > 0 || cmd->p2 > 0) {
if (cmd->p1 > 0 || cmd->p2 > 1) {
return io_send_sw(SW_WRONG_P1P2);
}

Expand All @@ -63,7 +63,7 @@ int apdu_dispatcher(const command_t *cmd) {
buf.size = cmd->lc;
buf.offset = 0;

return handler_get_public_key(&buf);
return handler_get_public_key(&buf, (bool) cmd->p2);
case SIGN_TX:
if ((cmd->p1 == P1_START && cmd->p2 != P2_MORE) || // first apdu must be the BIP44 path
cmd->p1 > P1_MAX || //
Expand Down
155 changes: 155 additions & 0 deletions src/common/base58.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*****************************************************************************
* (c) 2020 Ledger SAS.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/

#include <stddef.h> // size_t
#include <stdint.h> // uint*_t
#include <string.h> // memmove, memset
#include <stdbool.h> // bool

#include "base58.h"

uint8_t const BASE58_TABLE[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //
0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xFF, 0xFF, //
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, //
0x10, 0xFF, 0x11, 0x12, 0x13, 0x14, 0x15, 0xFF, 0x16, 0x17, 0x18, 0x19, //
0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //
0xFF, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, //
0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, //
0x37, 0x38, 0x39, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF //
};

char const BASE58_ALPHABET[] = {
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', //
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', //
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', //
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' //
};

int base58_decode(const char *in, size_t in_len, uint8_t *out, size_t out_len) {
uint8_t tmp[MAX_DEC_INPUT_SIZE] = {0};
uint8_t buffer[MAX_DEC_INPUT_SIZE] = {0};
uint8_t j;
uint8_t start_at;
uint8_t zero_count = 0;

if (in_len > MAX_DEC_INPUT_SIZE || in_len < 2) {
return -1;
}

memmove(tmp, in, in_len);

for (uint8_t i = 0; i < in_len; i++) {
if (in[i] >= sizeof(BASE58_TABLE)) {
return -1;
}

tmp[i] = BASE58_TABLE[(int) in[i]];

if (tmp[i] == 0xFF) {
return -1;
}
}

while ((zero_count < in_len) && (tmp[zero_count] == 0)) {
++zero_count;
}

j = in_len;
start_at = zero_count;
while (start_at < in_len) {
uint16_t remainder = 0;
for (uint8_t div_loop = start_at; div_loop < in_len; div_loop++) {
uint16_t digit256 = (uint16_t)(tmp[div_loop] & 0xFF);
uint16_t tmp_div = remainder * 58 + digit256;
tmp[div_loop] = (uint8_t)(tmp_div / 256);
remainder = tmp_div % 256;
}

if (tmp[start_at] == 0) {
++start_at;
}

buffer[--j] = (uint8_t) remainder;
}

while ((j < in_len) && (buffer[j] == 0)) {
++j;
}

int length = in_len - (j - zero_count);

if ((int) out_len < length) {
return -1;
}

memmove(out, buffer + j - zero_count, length);

return length;
}

int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len) {
uint8_t buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0};
size_t i, j;
size_t stop_at;
size_t zero_count = 0;
size_t output_size;

if (in_len > MAX_ENC_INPUT_SIZE) {
return -1;
}

while ((zero_count < in_len) && (in[zero_count] == 0)) {
++zero_count;
}

output_size = (in_len - zero_count) * 138 / 100 + 1;
stop_at = output_size - 1;
for (size_t start_at = zero_count; start_at < in_len; start_at++) {
int carry = in[start_at];
for (j = output_size - 1; (int) j >= 0; j--) {
carry += 256 * buffer[j];
buffer[j] = carry % 58;
carry /= 58;

if (j <= stop_at - 1 && carry == 0) {
break;
}
}
stop_at = j;
}

j = 0;
while (j < output_size && buffer[j] == 0) {
j += 1;
}

if (out_len < zero_count + output_size - j) {
return -1;
}

memset(out, BASE58_ALPHABET[0], zero_count);

i = zero_count;
while (j < output_size) {
out[i++] = BASE58_ALPHABET[buffer[j++]];
}

return i;
}
52 changes: 52 additions & 0 deletions src/common/base58.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

#include <stddef.h> // size_t
#include <stdint.h> // uint*_t
#include <stdbool.h> // bool

/**
* Maximum length of input when decoding in base 58.
*/
#define MAX_DEC_INPUT_SIZE 164
/**
* Maximum length of input when encoding in base 58.
*/
#define MAX_ENC_INPUT_SIZE 120

/**
* Decode input string in base 58.
*
* @see https://tools.ietf.org/html/draft-msporny-base58-02
*
* @param[in] in
* Pointer to input string buffer.
* @param[in] in_len
* Length of the input string buffer.
* @param[out] out
* Pointer to output byte buffer.
* @param[in] out_len
* Maximum length to write in output byte buffer.
*
* @return number of bytes decoded, -1 otherwise.
*
*/
int base58_decode(const char *in, size_t in_len, uint8_t *out, size_t out_len);

/**
* Encode input bytes in base 58.
*
* @see https://tools.ietf.org/html/draft-msporny-base58-02
*
* @param[in] in
* Pointer to input byte buffer.
* @param[in] in_len
* Length of the input byte buffer.
* @param[out] out
* Pointer to output string buffer.
* @param[in] out_len
* Maximum length to write in output byte buffer.
*
* @return number of bytes encoded, -1 otherwise.
*
*/
int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len);
11 changes: 8 additions & 3 deletions src/handler/get_public_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@
#include "../common/buffer.h"
#include "../common/bip44.h"
#include "../ui/display.h"
#include "../helper/send_response.h"

int handler_get_public_key(buffer_t *cdata) {
int handler_get_public_key(buffer_t *cdata, bool show_on_screen) {
explicit_bzero(&G_context, sizeof(G_context));
G_context.state = STATE_NONE;
G_context.state = CONFIRM_ADDRESS;

uint16_t status;
if (!buffer_read_and_validate_bip44(cdata, G_context.bip44_path, &status)) return io_send_sw(status);
Expand All @@ -51,5 +52,9 @@ int handler_get_public_key(buffer_t *cdata) {
// Clear private key
explicit_bzero(&private_key, sizeof(private_key));

return io_send_response(&(const buffer_t){.ptr = public_key.W, .size = 65, .offset = 0}, SW_OK);
if (show_on_screen) {
return ui_display_address();
}

return helper_send_response_pubkey();
}
4 changes: 2 additions & 2 deletions src/handler/get_public_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
*
* @param[in,out] cdata
* Command data with BIP44 path.
* @param[in] display
* @param[in] show_on_screen
* Whether to display address on screen or not.
*
* @return zero or positive integer if success, negative integer otherwise.
*
*/
int handler_get_public_key(buffer_t *cdata);
int handler_get_public_key(buffer_t *cdata, bool show_on_screen);
20 changes: 20 additions & 0 deletions src/helper/send_response.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <stddef.h> // size_t
#include <stdint.h> // uint*_t
#include <string.h> // memmove

#include "send_response.h"
#include "../constants.h"
#include "../globals.h"
#include "../sw.h"
#include "common/buffer.h"

int helper_send_response_pubkey() {
uint8_t resp[1 + PUBKEY_LEN] = {0};
size_t offset = 1;

resp[0] = 0x04;
memmove(resp + offset, G_context.raw_public_key, PUBKEY_LEN);
offset += PUBKEY_LEN;

return io_send_response(&(const buffer_t){.ptr = resp, .size = offset, .offset = 0}, SW_OK);
}
12 changes: 12 additions & 0 deletions src/helper/send_response.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include "os.h"

#include "../common/macros.h"

/**
* Length of public key.
*/
#define PUBKEY_LEN 64

int helper_send_response_pubkey(void);
7 changes: 6 additions & 1 deletion src/sw.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,9 @@
* Status word for failing to parse the network fee into a format that
* can be displayed on the device
*/
#define SW_DISPLAY_NETWORK_FEE_FAIL 0xb108
#define SW_DISPLAY_NETWORK_FEE_FAIL 0xb108

/**
* Status word for failing to convert public key to NEO address
*/
#define SW_CONVERT_TO_ADDRESS_FAIL 0xb200
2 changes: 1 addition & 1 deletion src/transaction/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <stddef.h> // size_t
#include <stdint.h> // uint*_t

#define ADDRESS_LEN 20
#define ADDRESS_LEN 34 // base58 encoded address size
#define UINT160_LEN 20
#define ECPOINT_LEN 33

Expand Down
11 changes: 11 additions & 0 deletions src/ui/action/validate.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@
#include "../../io.h"
#include "../../crypto.h"
#include "../../globals.h"
#include "../../helper/send_response.h"

void ui_action_validate_pubkey(bool approved) {
if (approved) {
helper_send_response_pubkey();
} else {
io_send_sw(SW_DENY);
}

ui_menu_main();
}

void ui_action_validate_transaction(bool approved) {
if (approved) {
Expand Down
9 changes: 9 additions & 0 deletions src/ui/action/validate.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

#include <stdbool.h> // bool

/**
* Action for public key validation and export.
*
* @param[in] approved
* User approved or rejected.
*
*/
void ui_action_validate_pubkey(bool approved);

/**
* Action for transaction information validation.
*
Expand Down
Loading

0 comments on commit f9735aa

Please sign in to comment.