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 "der_utils.h" 26 : #include <stddef.h> 27 : #include <stdbool.h> 28 : #include <string.h> 29 : 30 : // Helper function to encode a len-byte unsigned integer (R or S) in DER format 31 32 : static size_t der_encode_uint(uint8_t* dest, 32 : size_t dest_len, 33 : uint8_t* src, 34 : size_t src_len) { 35 : // Disallow zero-length uints 36 32 : if (src_len == 0) 37 0 : return 0; 38 : // Start of source: remove leading zeroes 39 32 : size_t trim = 0; 40 276 : while (!src[trim] && trim < (src_len - 1)) 41 244 : trim++; 42 : // Check if we need a leading zero byte 43 32 : bool lz = src[trim] & 0x80; 44 : // Validate destination buffer size 45 32 : if (dest_len < (2 + (lz ? 1 : 0) + src_len - trim)) 46 0 : return 0; 47 : // Output 48 32 : size_t off = 0; 49 32 : dest[off++] = 0x02; // Integer tag 50 32 : dest[off++] = src_len - trim + (lz ? 1 : 0); // Length byte 51 32 : if (lz) 52 10 : dest[off++] = 0x00; // Leading zero 53 32 : memcpy(dest + off, src + trim, src_len - trim); // Actual integer 54 32 : return (size_t)dest[1] + 2; 55 : } 56 : 57 16 : uint8_t der_encode_signature(uint8_t* dest, 58 : size_t dest_size, 59 : sgx_ecdsa256_signature_t* sig) { 60 : // Temporary buffers for R and S with 61 : // space for TLV with potential leading zero 62 : uint8_t r_encoded[sizeof(sig->r) + 3]; 63 : uint8_t s_encoded[sizeof(sig->r) + 3]; 64 32 : uint8_t r_len = (uint8_t)der_encode_uint( 65 16 : r_encoded, sizeof(r_encoded), sig->r, sizeof(sig->r)); 66 32 : uint8_t s_len = (uint8_t)der_encode_uint( 67 16 : s_encoded, sizeof(s_encoded), sig->s, sizeof(sig->s)); 68 : 69 : // Fail if errors happened during R or S encoding 70 16 : if (!r_len || !s_len) 71 0 : return 0; 72 : 73 : // Check for enough space in destination buffer 74 16 : if (dest_size < (size_t)(r_len + s_len + 2)) 75 8 : return 0; 76 : 77 : // Start the sequence 78 8 : dest[0] = 0x30; // Sequence tag 79 8 : dest[1] = r_len + s_len; // Length of the sequence 80 8 : memcpy(dest + 2, r_encoded, r_len); // Copy encoded R 81 8 : memcpy(dest + 2 + r_len, s_encoded, s_len); // Copy encoded S 82 : 83 : // Return total length of DER encoded signature 84 8 : return (uint8_t)(2 + r_len + s_len); 85 : }