/* Copyright (C) 2007 The Written Word, Inc. * Copyright (C) 2008, Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * Neither the name of the copyright holder nor the names * of any other contributors may be used to endorse or * promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #include "libssh2_priv.h" static int readline(char *line, int line_size, FILE * fp) { size_t len; if (!line) { return -1; } if (!fgets(line, line_size, fp)) { return -1; } if (*line) { len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; } } if (*line) { len = strlen(line); if (len > 0 && line[len - 1] == '\r') { line[len - 1] = '\0'; } } return 0; } static int readline_memory(char *line, size_t line_size, const char *filedata, size_t filedata_len, size_t *filedata_offset) { size_t off, len; off = *filedata_offset; for (len = 0; off + len < filedata_len && len < line_size; len++) { if (filedata[off + len] == '\n' || filedata[off + len] == '\r') { break; } } if (len) { memcpy(line, filedata + off, len); *filedata_offset += len; } line[len] = '\0'; *filedata_offset += 1; return 0; } #define LINE_SIZE 128 int _libssh2_pem_parse(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, FILE * fp, unsigned char **data, unsigned int *datalen) { char line[LINE_SIZE]; char *b64data = NULL; unsigned int b64datalen = 0; int ret; do { *line = '\0'; if (readline(line, LINE_SIZE, fp)) { return -1; } } while (strcmp(line, headerbegin) != 0); *line = '\0'; do { if (*line) { char *tmp; size_t linelen; linelen = strlen(line); tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); if (!tmp) { ret = -1; goto out; } memcpy(tmp + b64datalen, line, linelen); b64data = tmp; b64datalen += linelen; } *line = '\0'; if (readline(line, LINE_SIZE, fp)) { ret = -1; goto out; } } while (strcmp(line, headerend) != 0); if (!b64data) { return -1; } if (libssh2_base64_decode(session, (char**) data, datalen, b64data, b64datalen)) { ret = -1; goto out; } ret = 0; out: if (b64data) { LIBSSH2_FREE(session, b64data); } return ret; } int _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, const char *filedata, size_t filedata_len, unsigned char **data, unsigned int *datalen) { char line[LINE_SIZE]; char *b64data = NULL; unsigned int b64datalen = 0; size_t off = 0; int ret; do { *line = '\0'; if (readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { return -1; } } while (strcmp(line, headerbegin) != 0); *line = '\0'; do { if (*line) { char *tmp; size_t linelen; linelen = strlen(line); tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); if (!tmp) { ret = -1; goto out; } memcpy(tmp + b64datalen, line, linelen); b64data = tmp; b64datalen += linelen; } *line = '\0'; if (readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { ret = -1; goto out; } } while (strcmp(line, headerend) != 0); if (!b64data) { return -1; } if (libssh2_base64_decode(session, (char**) data, datalen, b64data, b64datalen)) { ret = -1; goto out; } ret = 0; out: if (b64data) { LIBSSH2_FREE(session, b64data); } return ret; } static int read_asn1_length(const unsigned char *data, unsigned int datalen, unsigned int *len) { unsigned int lenlen; int nextpos; if (datalen < 1) { return -1; } *len = data[0]; if (*len >= 0x80) { lenlen = *len & 0x7F; *len = data[1]; if (1 + lenlen > datalen) { return -1; } if (lenlen > 1) { *len <<= 8; *len |= data[2]; } } else { lenlen = 0; } nextpos = 1 + lenlen; if (lenlen > 2 || 1 + lenlen + *len > datalen) { return -1; } return nextpos; } int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen) { unsigned int len; int lenlen; if (*datalen < 1) { return -1; } if ((*data)[0] != '\x30') { return -1; } (*data)++; (*datalen)--; lenlen = read_asn1_length(*data, *datalen, &len); if (lenlen < 0 || lenlen + len != *datalen) { return -1; } *data += lenlen; *datalen -= lenlen; return 0; } int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, unsigned char **i, unsigned int *ilen) { unsigned int len; int lenlen; if (*datalen < 1) { return -1; } if ((*data)[0] != '\x02') { return -1; } (*data)++; (*datalen)--; lenlen = read_asn1_length(*data, *datalen, &len); if (lenlen < 0 || lenlen + len > *datalen) { return -1; } *data += lenlen; *datalen -= lenlen; *i = *data; *ilen = len; *data += len; *datalen -= len; return 0; }