LCOV - code coverage report
Current view: top level - ui/src - pin.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 32 38 84.2 %
Date: 2024-04-05 20:46:34 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /**
       2             :  * The MIT License (MIT)
       3             :  *
       4             :  * Copyright (c) 2021 RSK Labs Ltd
       5             :  *
       6             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       7             :  * of this software and associated documentation files (the "Software"), to
       8             :  * deal in the Software without restriction, including without limitation the
       9             :  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      10             :  * sell copies of the Software, and to permit persons to whom the Software is
      11             :  * furnished to do so, subject to the following conditions:
      12             :  *
      13             :  * The above copyright notice and this permission notice shall be included in
      14             :  * all copies or substantial portions of the Software.
      15             :  *
      16             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      17             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      18             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      19             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      20             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      21             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
      22             :  * IN THE SOFTWARE.
      23             :  */
      24             : 
      25             : #include <string.h>
      26             : 
      27             : #include "apdu.h"
      28             : #include "os.h"
      29             : #include "ui_err.h"
      30             : #include "pin.h"
      31             : 
      32             : // Helper macros for pin validation
      33             : #define IS_IN_RANGE(c, begin, end) (((c) >= (begin)) && ((c) <= (end)))
      34             : #define IS_ALPHA(c) (IS_IN_RANGE(c, 'a', 'z') || IS_IN_RANGE(c, 'A', 'Z'))
      35             : #define IS_NUM(c) IS_IN_RANGE(c, '0', '9')
      36             : #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
      37             : 
      38             : #define PIN_LENGTH 8
      39             : #define PIN_BUFFER_LENGTH (PIN_LENGTH + 2)
      40             : // Internal PIN buffer used for authenticated operations
      41             : unsigned char G_pin_buffer[PIN_BUFFER_LENGTH];
      42             : // Helper macros for pin manipulation when prepended length is used
      43             : #define GET_PIN() ((unsigned char *)(G_pin_buffer + 1))
      44             : #define GET_PIN_LENGTH() strlen((const char *)GET_PIN())
      45             : 
      46             : /*
      47             :  * Implements RSK PIN command.
      48             :  *
      49             :  * Receives one byte at a time and updates the pin context, adding a null byte
      50             :  * at the end.
      51             :  *
      52             :  * @arg[in] rx      number of received bytes from the Host
      53             :  * @ret             number of transmited bytes to the host
      54             :  */
      55         240 : unsigned int update_pin_buffer(volatile unsigned int rx) {
      56             :     // Should receive 1 byte per call
      57         240 :     if (APDU_DATA_SIZE(rx) != 1) {
      58           0 :         THROW(ERR_UI_PROT_INVALID);
      59             :     }
      60             : 
      61         240 :     unsigned char index = APDU_OP();
      62         240 :     if ((index >= 0) && (index <= PIN_LENGTH)) {
      63         223 :         G_pin_buffer[index] = APDU_AT(DATA);
      64         223 :         G_pin_buffer[index + 1] = 0;
      65             :     }
      66             : 
      67         240 :     return 3;
      68             : }
      69             : 
      70             : /*
      71             :  * Implements RSK NEW PIN command.
      72             :  *
      73             :  * Sets and checks the device pin.
      74             :  *
      75             :  * @ret number of transmited bytes to the host
      76             :  */
      77           5 : unsigned int set_pin() {
      78             : #ifndef DEBUG_BUILD
      79           5 :     if (!is_pin_valid()) {
      80           1 :         THROW(ERR_UI_INVALID_PIN);
      81             :     }
      82             : #endif
      83             :     // Set PIN
      84           4 :     os_perso_set_pin(0, GET_PIN(), GET_PIN_LENGTH());
      85             :     // check PIN
      86           4 :     os_global_pin_invalidate();
      87           4 :     unsigned char output_index = CMDPOS;
      88           4 :     SET_APDU_AT(output_index++, 2);
      89           4 :     SET_APDU_AT(output_index++,
      90             :                 os_global_pin_check(GET_PIN(), GET_PIN_LENGTH()));
      91           4 :     return output_index;
      92             : }
      93             : 
      94             : /*
      95             :  * Validates that the pin curently saved to the internal buffer has exactly
      96             :  * PIN_LENGTH alphanumeric characters with at least one alphabetic character.
      97             :  *
      98             :  * @ret     true if pin is valid, false otherwise
      99             :  */
     100          25 : bool is_pin_valid() {
     101             :     // PIN_LENGTH is the only length accepted
     102          25 :     if (GET_PIN_LENGTH() != PIN_LENGTH) {
     103           9 :         return false;
     104             :     }
     105             :     // Check if PIN is alphanumeric
     106          16 :     bool hasAlpha = false;
     107         136 :     for (int i = 0; i < PIN_LENGTH; i++) {
     108         121 :         if (!IS_ALPHANUM(GET_PIN()[i])) {
     109           1 :             return false;
     110             :         }
     111         120 :         if (hasAlpha || IS_ALPHA(GET_PIN()[i])) {
     112          66 :             hasAlpha = true;
     113             :         }
     114             :     }
     115             : 
     116          15 :     return hasAlpha;
     117             : }
     118             : 
     119             : /*
     120             :  * Fills the internal pin buffer with zeroes
     121             :  */
     122           0 : void clear_pin() {
     123           0 :     explicit_bzero(G_pin_buffer, sizeof(G_pin_buffer));
     124           0 : }
     125             : 
     126             : /*
     127             :  * Uses the pin currently saved to the internal pin buffer to unlock the device
     128             :  *
     129             :  * @arg[in] prepended_length true if the internal buffer includes a prepended
     130             :  *                           length byte, false otherwise
     131             :  * @ret                      1 if pin validated successfully, 0 otherwise
     132             :  */
     133           4 : unsigned int unlock_with_pin(bool prepended_length) {
     134           4 :     if (prepended_length) {
     135           4 :         return os_global_pin_check(GET_PIN(), GET_PIN_LENGTH());
     136             :     } else {
     137           0 :         return os_global_pin_check(G_pin_buffer,
     138           0 :                                    strlen((const char *)G_pin_buffer));
     139             :     }
     140             : }
     141             : 
     142             : /*
     143             :  * Sets the pin currently saved to the internal pin buffer as the device's pin.
     144             :  * This function assumes the pin is saved with a prepended length byte.
     145             :  */
     146           1 : void set_device_pin() {
     147           1 :     os_perso_set_pin(0, GET_PIN(), GET_PIN_LENGTH());
     148           1 : }

Generated by: LCOV version 1.14