Make base-64-encoded DER work, including workaround for ugly openssl misfeature that makes base64 decoding fail when you strip out the newlines.

svn:r2423
This commit is contained in:
Nick Mathewson 2004-10-07 03:11:42 +00:00
parent 2bba65148b
commit ce3162d035
5 changed files with 73 additions and 34 deletions

View File

@ -463,48 +463,67 @@ crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env,
return r; return r;
} }
int crypto_pk_DER64_encode_key(crypto_pk_env_t *env, char **out) /** Allocate a new string in *<b>out</b>, containing the public portion of the
* RSA key in <b>env</b>, encoded first with DER, then in base-64. Return the
* length of the encoded representation on success, and -1 on failure.
*
* <i>This function is for temporary use only. We need a simple
* one-line representation for keys to work around a bug in parsing
* directories containing "opt keyword\n-----BEGIN OBJECT----" entries
* in versions of Tor up to 0.0.9pre2.</i>
*/
int crypto_pk_DER64_encode_public_key(crypto_pk_env_t *env, char **out)
{ {
int len; int len;
char *s, *sp; char buf[PK_BYTES*2]; /* Too long, but hey, stacks are big. */
tor_assert(env && out); tor_assert(env && out);
len = i2d_RSAPublicKey(env->key, NULL); len = crypto_pk_asn1_encode(env, buf, sizeof(buf));
if (len < 0) { if (len < 0) {
return -1; return -1;
} }
s = sp = tor_malloc(len+1);
i2d_RSAPublicKey(env->key, &sp); /* modifies sp */
*out = tor_malloc(len * 2); /* too long, but safe. */ *out = tor_malloc(len * 2); /* too long, but safe. */
if (base64_encode(*out, len*2, s, len) < 0) { if (base64_encode(*out, len*2, buf, len) < 0) {
log_fn(LOG_WARN, "Error base64-encoding DER-encoded key"); log_fn(LOG_WARN, "Error base64-encoding DER-encoded key");
tor_free(*out); tor_free(*out);
tor_free(s);
return -1; return -1;
} }
tor_free(s); /* Remove spaces */
return len; tor_strstrip(*out, " \r\n\t");
return strlen(*out);
} }
int crypto_pk_DER64_decode_key(crypto_pk_env_t *env, const char *in) /** Decode a base-64 encoded DER representation of an RSA key from <b>in</b>,
* and store the result in <b>env</b>. Return 0 on success, -1 on failure.
*
* <i>This function is for temporary use only. We need a simple
* one-line representation for keys to work around a bug in parsing
* directories containing "opt keyword\n-----BEGIN OBJECT----" entries
* in versions of Tor up to 0.0.9pre2.</i>
*/
crypto_pk_env_t *crypto_pk_DER64_decode_public_key(const char *in)
{ {
char *buf, *bufp; char buf1[PK_BYTES*2 + PK_BYTES/64 + 2];
RSA *rsa; char buf[PK_BYTES*2];
int len; int len;
tor_assert(env && in); int i;
tor_assert(in);
len = strlen(in); len = strlen(in);
buf = bufp = tor_malloc(len+1);
if (base64_decode(buf, len+1, in, len)<0) { if (strlen(in) > PK_BYTES*2) {
tor_free(buf); return NULL;
log_fn(LOG_WARN,"Error base-64 decoding key");
return -1;
} }
rsa = d2i_RSAPublicKey(NULL, &bufp, strlen(buf)); /* base64_decode doesn't work unless we insert linebreaks every 64
tor_free(buf); * characters. how dumb. */
if (!rsa) for(i=0;i*64<len;i+=1) {
return -1; strncpy(buf1+(64+1)*i, in+64*i, 64);
if (env->key) RSA_free(env->key); strcpy(buf1+(64+1)*i + 64, "\n");
env->key = rsa; }
return 0; len = base64_decode(buf, sizeof(buf), buf1, strlen(buf1));
if (len<0) {
log_fn(LOG_WARN,"Error base-64 decoding key");
return NULL;
}
return crypto_pk_asn1_decode(buf, len);
} }
/** Return true iff <b>env</b> has a valid key. /** Return true iff <b>env</b> has a valid key.

View File

@ -64,6 +64,9 @@ int crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, const char *src,
int crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env, const char *fname); int crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env, const char *fname);
int crypto_pk_check_key(crypto_pk_env_t *env); int crypto_pk_check_key(crypto_pk_env_t *env);
int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, const char *keyfile); int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, const char *keyfile);
int crypto_pk_DER64_encode_public_key(crypto_pk_env_t *env, char **dest);
crypto_pk_env_t *crypto_pk_DER64_decode_public_key(const char *in);
int crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b); int crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b);
crypto_pk_env_t *crypto_pk_dup_key(crypto_pk_env_t *orig); crypto_pk_env_t *crypto_pk_dup_key(crypto_pk_env_t *orig);

View File

@ -87,6 +87,7 @@ char *tor_strndup(const char *s, size_t n);
#define tor_free(p) do {if(p) {free(p); (p)=NULL;}} while(0) #define tor_free(p) do {if(p) {free(p); (p)=NULL;}} while(0)
void tor_strlower(char *s); void tor_strlower(char *s);
int strcmpstart(const char *s1, const char *s2); int strcmpstart(const char *s1, const char *s2);
int tor_strstrip(char *s, const char *strip);
/* Some platforms segfault when you try to access a multi-byte type /* Some platforms segfault when you try to access a multi-byte type
* that isn't aligned to a word boundary. The macros and/or functions * that isn't aligned to a word boundary. The macros and/or functions

View File

@ -557,7 +557,7 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
char signature[128]; char signature[128];
char published[33]; char published[33];
time_t published_on; time_t published_on;
int i, identity_pkeylen; int i;
eos = s+maxlen; eos = s+maxlen;
if (!descriptor_list) if (!descriptor_list)
@ -565,14 +565,15 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
if (list_running_servers(&cp)) if (list_running_servers(&cp))
return -1; return -1;
#if 0
/* PEM-encode the identity key key */ /* ASN.1-encode the public key. This is a temporary measure; once
if(crypto_pk_write_public_key_to_string(private_key, * everyone is running 0.0.9pre3 or later, we can shift to using a
&identity_pkey,&identity_pkeylen)<0) { * PEM-encoded key instead.
*/
if(crypto_pk_DER64_encode_public_key(private_key, &identity_pkey)<0) {
log_fn(LOG_WARN,"write identity_pkey to string failed!"); log_fn(LOG_WARN,"write identity_pkey to string failed!");
return -1; return -1;
} }
#endif
dirserv_remove_old_servers(ROUTER_MAX_AGE); dirserv_remove_old_servers(ROUTER_MAX_AGE);
published_on = time(NULL); published_on = time(NULL);
format_iso_time(published, published_on); format_iso_time(published, published_on);
@ -580,8 +581,9 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
"signed-directory\n" "signed-directory\n"
"published %s\n" "published %s\n"
"recommended-software %s\n" "recommended-software %s\n"
"running-routers %s\n\n", "running-routers %s\n"
published, options.RecommendedVersions, cp); "opt dir-signing-key %s\n\n",
published, options.RecommendedVersions, cp, identity_pkey);
tor_free(cp); tor_free(cp);
tor_free(identity_pkey); tor_free(identity_pkey);

View File

@ -365,6 +365,20 @@ test_crypto()
test_assert(! crypto_pk_write_public_key_to_string(pk1, &cp, &i)); test_assert(! crypto_pk_write_public_key_to_string(pk1, &cp, &i));
test_assert(! crypto_pk_read_public_key_from_string(pk2, cp, i)); test_assert(! crypto_pk_read_public_key_from_string(pk2, cp, i));
test_eq(0, crypto_pk_cmp_keys(pk1, pk2)); test_eq(0, crypto_pk_cmp_keys(pk1, pk2));
tor_free(cp);
/* Check DER encoding */
i=crypto_pk_DER64_encode_public_key(pk1, &cp);
test_assert(i>0);
test_assert(cp);
test_assert(!strchr(cp, ' '));
test_assert(!strchr(cp, '\n'));
test_eq(0, crypto_pk_cmp_keys(pk1, pk1));
crypto_free_pk_env(pk2);
pk2 = crypto_pk_DER64_decode_public_key(cp);
test_assert(pk2);
test_eq(0, crypto_pk_cmp_keys(pk1, pk2));
tor_free(cp);
test_eq(128, crypto_pk_keysize(pk1)); test_eq(128, crypto_pk_keysize(pk1));
test_eq(128, crypto_pk_keysize(pk2)); test_eq(128, crypto_pk_keysize(pk2));
@ -1095,6 +1109,7 @@ main(int c, char**v){
// puts("========================== Buffers ========================="); // puts("========================== Buffers =========================");
// test_buffers(); // test_buffers();
puts("\n========================== Crypto =========================="); puts("\n========================== Crypto ==========================");
// add_stream_log(LOG_DEBUG, LOG_ERR, "<stdout>", stdout);
test_crypto(); test_crypto();
test_crypto_dh(); test_crypto_dh();
puts("\n========================= Util ============================"); puts("\n========================= Util ============================");
@ -1105,7 +1120,6 @@ main(int c, char**v){
test_onion(); test_onion();
test_onion_handshake(); test_onion_handshake();
puts("\n========================= Directory Formats ==============="); puts("\n========================= Directory Formats ===============");
/* add_stream_log(LOG_DEBUG, LOG_ERR, "<stdout>", stdout); */
test_dir_format(); test_dir_format();
puts("\n========================= Rendezvous functionality ========"); puts("\n========================= Rendezvous functionality ========");
test_rend_fns(); test_rend_fns();