int s2n_stuffer_write_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *in, uint32_t n) { gte_check(s2n_stuffer_space_remaining(stuffer), n * 2); for (int i = 0; i < n; i++) { uint8_t c; GUARD(s2n_stuffer_read_uint8(in, &c)); GUARD(s2n_stuffer_write_uint8_hex(stuffer, c)); } return 0; }
static int s2n_stuffer_pem_read_contents(struct s2n_stuffer *pem, struct s2n_stuffer *asn1) { uint8_t base64_buf[64] = { 0 }; struct s2n_blob base64__blob = { .data = base64_buf, .size = sizeof(base64_buf) }; struct s2n_stuffer base64_stuffer = {{0}}; GUARD(s2n_stuffer_init(&base64_stuffer, &base64__blob)); while (1) { char c; /* Peek to see if the next char is a dash, meaning end of pem_contents */ GUARD(s2n_stuffer_peek_char(pem, &c)); if (c == '-') { break; } else { /* Else, move read pointer forward by 1 byte since we will be consuming it. */ GUARD(s2n_stuffer_skip_read(pem, 1)); } /* Skip non-base64 characters */ if (!s2n_is_base64_char(c)) { continue; } /* Flush base64_stuffer to asn1 stuffer if we're out of space, and reset base64_stuffer read/write pointers */ if (s2n_stuffer_space_remaining(&base64_stuffer) == 0) { GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1)); GUARD(s2n_stuffer_rewrite(&base64_stuffer)); } /* Copy next char to base64_stuffer */ GUARD(s2n_stuffer_write_bytes(&base64_stuffer, (uint8_t *) &c, 1)); }; /* Flush any remaining bytes to asn1 */ GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1)); return 0; } static int s2n_stuffer_data_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1, const char *keyword) { GUARD(s2n_stuffer_pem_read_begin(pem, keyword)); GUARD(s2n_stuffer_pem_read_contents(pem, asn1)); GUARD(s2n_stuffer_pem_read_end(pem, keyword)); return 0; }
/* Due to the need to support some older assemblers, * we cannot use either the compiler intrinsics or * the RDRAND assembly mnemonic. For this reason, * we're using the opcode directly (0F C7/6). This * stores the result in eax. * * volatile is important to prevent the compiler from * re-ordering or optimizing the use of RDRAND. */ int s2n_get_rdrand_data(struct s2n_blob *out) { #if defined(__x86_64__)||defined(__i386__) int space_remaining = 0; struct s2n_stuffer stuffer; union { uint64_t u64; uint8_t u8[8]; } output; GUARD(s2n_stuffer_init(&stuffer, out)); while((space_remaining = s2n_stuffer_space_remaining(&stuffer))) { int success = 0; for (int tries = 0; tries < 10; tries++) { __asm__ __volatile__( ".byte 0x48;\n" ".byte 0x0f;\n" ".byte 0xc7;\n" ".byte 0xf0;\n" "adcl $0x00, %%ebx;\n" :"=b"(success), "=a"(output.u64) :"b"(0) :"cc" ); if (success) { break; } } if (!success) { return -1; } int data_to_fill = MIN(sizeof(output), space_remaining); GUARD(s2n_stuffer_write_bytes(&stuffer, output.u8, data_to_fill)); } return 0; #else return -1; #endif }
int s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, const uint32_t n) { if (s2n_stuffer_space_remaining(stuffer) < n) { if (stuffer->growable) { /* Always grow a stuffer by at least 1k */ uint32_t growth = n; if (growth < 1024) { growth = 1024; } GUARD(s2n_stuffer_resize(stuffer, stuffer->blob.size + growth)); } else { S2N_ERROR(S2N_ERR_STUFFER_IS_FULL); } } stuffer->write_cursor += n; stuffer->wiped = 0; return 0; }
/** * Helper function: read n bits of hex data. */ static int s2n_stuffer_read_n_bits_hex(struct s2n_stuffer *stuffer, uint8_t n, uint64_t *u) { uint8_t hex_data[16]; struct s2n_blob b = { .data = hex_data, .size = n / 4 }; GUARD(s2n_stuffer_read(stuffer, &b)); /* Start with u = 0 */ *u = 0; for (int i = 0; i < b.size; i++) { *u <<= 4; if (b.data[i] >= '0' && b.data[i] <= '9') { *u |= b.data[i] - '0'; } else if (b.data[i] >= 'a' && b.data[i] <= 'f') { *u |= b.data[i] - 'a' + 10; } else if (b.data[i] >= 'A' && b.data[i] <= 'F') { *u |= b.data[i] - 'A' + 10; } else { S2N_ERROR(S2N_ERR_BAD_MESSAGE); } } return 0; } int s2n_stuffer_read_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *out, uint32_t n) { gte_check(s2n_stuffer_space_remaining(out), n); for (int i = 0; i < n; i++) { uint8_t c; GUARD(s2n_stuffer_read_uint8_hex(stuffer, &c)); GUARD(s2n_stuffer_write_uint8(out, c)); } return 0; }