123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902 |
- /* 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 - 1; 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
- static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED";
- static unsigned char hex_decode(char digit)
- {
- return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0');
- }
- int
- _libssh2_pem_parse(LIBSSH2_SESSION * session,
- const char *headerbegin,
- const char *headerend,
- const unsigned char *passphrase,
- FILE * fp, unsigned char **data, unsigned int *datalen)
- {
- char line[LINE_SIZE];
- unsigned char iv[LINE_SIZE];
- char *b64data = NULL;
- unsigned int b64datalen = 0;
- int ret;
- const LIBSSH2_CRYPT_METHOD *method = NULL;
- do {
- *line = '\0';
- if(readline(line, LINE_SIZE, fp)) {
- return -1;
- }
- }
- while(strcmp(line, headerbegin) != 0);
- if(readline(line, LINE_SIZE, fp)) {
- return -1;
- }
- if(passphrase &&
- memcmp(line, crypt_annotation, strlen(crypt_annotation)) == 0) {
- const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
- int i;
- if(readline(line, LINE_SIZE, fp)) {
- ret = -1;
- goto out;
- }
- all_methods = libssh2_crypt_methods();
- while((cur_method = *all_methods++)) {
- if(*cur_method->pem_annotation &&
- memcmp(line, cur_method->pem_annotation,
- strlen(cur_method->pem_annotation)) == 0) {
- method = cur_method;
- memcpy(iv, line + strlen(method->pem_annotation) + 1,
- 2*method->iv_len);
- }
- }
- /* None of the available crypt methods were able to decrypt the key */
- if(method == NULL)
- return -1;
- /* Decode IV from hex */
- for(i = 0; i < method->iv_len; ++i) {
- iv[i] = hex_decode(iv[2*i]) << 4;
- iv[i] |= hex_decode(iv[2*i + 1]);
- }
- /* skip to the next line */
- if(readline(line, LINE_SIZE, fp)) {
- ret = -1;
- goto out;
- }
- }
- 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;
- }
- if(method) {
- /* Set up decryption */
- int free_iv = 0, free_secret = 0, len_decrypted = 0, padding = 0;
- int blocksize = method->blocksize;
- void *abstract;
- unsigned char secret[2*MD5_DIGEST_LENGTH];
- libssh2_md5_ctx fingerprint_ctx;
- /* Perform key derivation (PBKDF1/MD5) */
- if(!libssh2_md5_init(&fingerprint_ctx)) {
- ret = -1;
- goto out;
- }
- libssh2_md5_update(fingerprint_ctx, passphrase,
- strlen((char *)passphrase));
- libssh2_md5_update(fingerprint_ctx, iv, 8);
- libssh2_md5_final(fingerprint_ctx, secret);
- if(method->secret_len > MD5_DIGEST_LENGTH) {
- if(!libssh2_md5_init(&fingerprint_ctx)) {
- ret = -1;
- goto out;
- }
- libssh2_md5_update(fingerprint_ctx, secret, MD5_DIGEST_LENGTH);
- libssh2_md5_update(fingerprint_ctx, passphrase,
- strlen((char *)passphrase));
- libssh2_md5_update(fingerprint_ctx, iv, 8);
- libssh2_md5_final(fingerprint_ctx, secret + MD5_DIGEST_LENGTH);
- }
- /* Initialize the decryption */
- if(method->init(session, method, iv, &free_iv, secret,
- &free_secret, 0, &abstract)) {
- _libssh2_explicit_zero((char *)secret, sizeof(secret));
- LIBSSH2_FREE(session, data);
- ret = -1;
- goto out;
- }
- if(free_secret) {
- _libssh2_explicit_zero((char *)secret, sizeof(secret));
- }
- /* Do the actual decryption */
- if((*datalen % blocksize) != 0) {
- _libssh2_explicit_zero((char *)secret, sizeof(secret));
- method->dtor(session, &abstract);
- _libssh2_explicit_zero(*data, *datalen);
- LIBSSH2_FREE(session, *data);
- ret = -1;
- goto out;
- }
- while(len_decrypted <= (int)*datalen - blocksize) {
- if(method->crypt(session, *data + len_decrypted, blocksize,
- &abstract)) {
- ret = LIBSSH2_ERROR_DECRYPT;
- _libssh2_explicit_zero((char *)secret, sizeof(secret));
- method->dtor(session, &abstract);
- _libssh2_explicit_zero(*data, *datalen);
- LIBSSH2_FREE(session, *data);
- goto out;
- }
- len_decrypted += blocksize;
- }
- /* Account for padding */
- padding = (*data)[*datalen - 1];
- memset(&(*data)[*datalen-padding], 0, padding);
- *datalen -= padding;
- /* Clean up */
- _libssh2_explicit_zero((char *)secret, sizeof(secret));
- method->dtor(session, &abstract);
- }
- ret = 0;
- out:
- if(b64data) {
- _libssh2_explicit_zero(b64data, b64datalen);
- 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_explicit_zero(b64data, b64datalen);
- LIBSSH2_FREE(session, b64data);
- }
- return ret;
- }
- /* OpenSSH formatted keys */
- #define AUTH_MAGIC "openssh-key-v1"
- #define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
- #define OPENSSH_HEADER_END "-----END OPENSSH PRIVATE KEY-----"
- static int
- _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
- const unsigned char *passphrase,
- const char *b64data, size_t b64datalen,
- struct string_buf **decrypted_buf)
- {
- const LIBSSH2_CRYPT_METHOD *method = NULL;
- struct string_buf decoded, decrypted, kdf_buf;
- unsigned char *ciphername = NULL;
- unsigned char *kdfname = NULL;
- unsigned char *kdf = NULL;
- unsigned char *buf = NULL;
- unsigned char *salt = NULL;
- uint32_t nkeys, check1, check2;
- uint32_t rounds = 0;
- unsigned char *key = NULL;
- unsigned char *key_part = NULL;
- unsigned char *iv_part = NULL;
- unsigned char *f = NULL;
- unsigned int f_len = 0;
- int ret = 0, keylen = 0, ivlen = 0, total_len = 0;
- size_t kdf_len = 0, tmp_len = 0, salt_len = 0;
- if(decrypted_buf)
- *decrypted_buf = NULL;
- /* decode file */
- if(libssh2_base64_decode(session, (char **)&f, &f_len,
- b64data, b64datalen)) {
- ret = -1;
- goto out;
- }
- /* Parse the file */
- decoded.data = (unsigned char *)f;
- decoded.dataptr = (unsigned char *)f;
- decoded.len = f_len;
- if(decoded.len < strlen(AUTH_MAGIC)) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "key too short");
- goto out;
- }
- if(strncmp((char *) decoded.dataptr, AUTH_MAGIC,
- strlen(AUTH_MAGIC)) != 0) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "key auth magic mismatch");
- goto out;
- }
- decoded.dataptr += strlen(AUTH_MAGIC) + 1;
- if(_libssh2_get_string(&decoded, &ciphername, &tmp_len) ||
- tmp_len == 0) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "ciphername is missing");
- goto out;
- }
- if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) ||
- tmp_len == 0) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "kdfname is missing");
- goto out;
- }
- if(_libssh2_get_string(&decoded, &kdf, &kdf_len)) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "kdf is missing");
- goto out;
- }
- else {
- kdf_buf.data = kdf;
- kdf_buf.dataptr = kdf;
- kdf_buf.len = kdf_len;
- }
- if((passphrase == NULL || strlen((const char *)passphrase) == 0) &&
- strcmp((const char *)ciphername, "none") != 0) {
- /* passphrase required */
- ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
- goto out;
- }
- if(strcmp((const char *)kdfname, "none") != 0 &&
- strcmp((const char *)kdfname, "bcrypt") != 0) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "unknown cipher");
- goto out;
- }
- if(!strcmp((const char *)kdfname, "none") &&
- strcmp((const char *)ciphername, "none") != 0) {
- ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "invalid format");
- goto out;
- }
- if(_libssh2_get_u32(&decoded, &nkeys) != 0 || nkeys != 1) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Multiple keys are unsupported");
- goto out;
- }
- /* unencrypted public key */
- if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Invalid private key; "
- "expect embedded public key");
- goto out;
- }
- if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Private key data not found");
- goto out;
- }
- /* decode encrypted private key */
- decrypted.data = decrypted.dataptr = buf;
- decrypted.len = tmp_len;
- if(ciphername && strcmp((const char *)ciphername, "none") != 0) {
- const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
- all_methods = libssh2_crypt_methods();
- while((cur_method = *all_methods++)) {
- if(*cur_method->name &&
- memcmp(ciphername, cur_method->name,
- strlen(cur_method->name)) == 0) {
- method = cur_method;
- }
- }
- /* None of the available crypt methods were able to decrypt the key */
- if(method == NULL) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "No supported cipher found");
- goto out;
- }
- }
- if(method) {
- int free_iv = 0, free_secret = 0, len_decrypted = 0;
- int blocksize;
- void *abstract = NULL;
- keylen = method->secret_len;
- ivlen = method->iv_len;
- total_len = keylen + ivlen;
- key = LIBSSH2_CALLOC(session, total_len);
- if(key == NULL) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Could not alloc key");
- goto out;
- }
- if(strcmp((const char *)kdfname, "bcrypt") == 0 &&
- passphrase != NULL) {
- if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) ||
- (_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "kdf contains unexpected values");
- LIBSSH2_FREE(session, key);
- goto out;
- }
- if(_libssh2_bcrypt_pbkdf((const char *)passphrase,
- strlen((const char *)passphrase),
- salt, salt_len, key,
- keylen + ivlen, rounds) < 0) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
- "invalid format");
- LIBSSH2_FREE(session, key);
- goto out;
- }
- }
- else {
- ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED,
- "bcrypted without passphrase");
- LIBSSH2_FREE(session, key);
- goto out;
- }
- /* Set up decryption */
- blocksize = method->blocksize;
- key_part = LIBSSH2_CALLOC(session, keylen);
- if(key_part == NULL) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Could not alloc key part");
- goto out;
- }
- iv_part = LIBSSH2_CALLOC(session, ivlen);
- if(iv_part == NULL) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Could not alloc iv part");
- goto out;
- }
- memcpy(key_part, key, keylen);
- memcpy(iv_part, key + keylen, ivlen);
- /* Initialize the decryption */
- if(method->init(session, method, iv_part, &free_iv, key_part,
- &free_secret, 0, &abstract)) {
- ret = LIBSSH2_ERROR_DECRYPT;
- goto out;
- }
- /* Do the actual decryption */
- if((decrypted.len % blocksize) != 0) {
- method->dtor(session, &abstract);
- ret = LIBSSH2_ERROR_DECRYPT;
- goto out;
- }
- while((size_t)len_decrypted <= decrypted.len - blocksize) {
- if(method->crypt(session, decrypted.data + len_decrypted,
- blocksize,
- &abstract)) {
- ret = LIBSSH2_ERROR_DECRYPT;
- method->dtor(session, &abstract);
- goto out;
- }
- len_decrypted += blocksize;
- }
- /* No padding */
- method->dtor(session, &abstract);
- }
- /* Check random bytes match */
- if(_libssh2_get_u32(&decrypted, &check1) != 0 ||
- _libssh2_get_u32(&decrypted, &check2) != 0 ||
- check1 != check2) {
- _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Private key unpack failed (correct password?)");
- ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
- goto out;
- }
- if(decrypted_buf != NULL) {
- /* copy data to out-going buffer */
- struct string_buf *out_buf = _libssh2_string_buf_new(session);
- if(!out_buf) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
- "Unable to allocate memory for "
- "decrypted struct");
- goto out;
- }
- out_buf->data = LIBSSH2_CALLOC(session, decrypted.len);
- if(out_buf->data == NULL) {
- ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
- "Unable to allocate memory for "
- "decrypted struct");
- _libssh2_string_buf_free(session, out_buf);
- goto out;
- }
- memcpy(out_buf->data, decrypted.data, decrypted.len);
- out_buf->dataptr = out_buf->data +
- (decrypted.dataptr - decrypted.data);
- out_buf->len = decrypted.len;
- *decrypted_buf = out_buf;
- }
- out:
- /* Clean up */
- if(key) {
- _libssh2_explicit_zero(key, total_len);
- LIBSSH2_FREE(session, key);
- }
- if(key_part) {
- _libssh2_explicit_zero(key_part, keylen);
- LIBSSH2_FREE(session, key_part);
- }
- if(iv_part) {
- _libssh2_explicit_zero(iv_part, ivlen);
- LIBSSH2_FREE(session, iv_part);
- }
- if(f) {
- _libssh2_explicit_zero(f, f_len);
- LIBSSH2_FREE(session, f);
- }
- return ret;
- }
- int
- _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
- const unsigned char *passphrase,
- FILE * fp, struct string_buf **decrypted_buf)
- {
- char line[LINE_SIZE];
- char *b64data = NULL;
- unsigned int b64datalen = 0;
- int ret = 0;
- /* read file */
- do {
- *line = '\0';
- if(readline(line, LINE_SIZE, fp)) {
- return -1;
- }
- }
- while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
- if(readline(line, LINE_SIZE, fp)) {
- return -1;
- }
- 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, OPENSSH_HEADER_END) != 0);
- if(!b64data) {
- return -1;
- }
- ret = _libssh2_openssh_pem_parse_data(session,
- passphrase,
- (const char *)b64data,
- (size_t)b64datalen,
- decrypted_buf);
- if(b64data) {
- _libssh2_explicit_zero(b64data, b64datalen);
- LIBSSH2_FREE(session, b64data);
- }
- out:
- return ret;
- }
- int
- _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
- const unsigned char *passphrase,
- const char *filedata, size_t filedata_len,
- struct string_buf **decrypted_buf)
- {
- char line[LINE_SIZE];
- char *b64data = NULL;
- unsigned int b64datalen = 0;
- size_t off = 0;
- int ret;
- if(filedata == NULL || filedata_len <= 0) {
- return -1;
- }
- do {
- *line = '\0';
- if(off >= filedata_len) {
- return -1;
- }
- if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
- return -1;
- }
- }
- while(strcmp(line, OPENSSH_HEADER_BEGIN) != 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(off >= filedata_len) {
- ret = -1;
- goto out;
- }
- if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
- ret = -1;
- goto out;
- }
- } while(strcmp(line, OPENSSH_HEADER_END) != 0);
- if(!b64data) {
- return -1;
- }
- ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data,
- b64datalen, decrypted_buf);
- out:
- if(b64data) {
- _libssh2_explicit_zero(b64data, b64datalen);
- 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;
- }
|