diff options
author | Nick Mathewson <nickm@torproject.org> | 2004-10-07 03:11:42 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2004-10-07 03:11:42 +0000 |
commit | ce3162d03510c9e87c508d4b854757bb501f8461 (patch) | |
tree | a404418b94b5b4a6a97d5be9f9e4fc5d8dce39d3 /src | |
parent | 2bba65148bd8b427bf3bb5753c371da8395552fc (diff) | |
download | tor-ce3162d03510c9e87c508d4b854757bb501f8461.tar tor-ce3162d03510c9e87c508d4b854757bb501f8461.tar.gz |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/common/crypto.c | 67 | ||||
-rw-r--r-- | src/common/crypto.h | 3 | ||||
-rw-r--r-- | src/common/util.h | 1 | ||||
-rw-r--r-- | src/or/dirserv.c | 18 | ||||
-rw-r--r-- | src/or/test.c | 16 |
5 files changed, 72 insertions, 33 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index ea5d76d91..b6ec9a7b7 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -463,48 +463,67 @@ crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env, 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; - char *s, *sp; + char buf[PK_BYTES*2]; /* Too long, but hey, stacks are big. */ tor_assert(env && out); - len = i2d_RSAPublicKey(env->key, NULL); + len = crypto_pk_asn1_encode(env, buf, sizeof(buf)); if (len < 0) { return -1; } - s = sp = tor_malloc(len+1); - i2d_RSAPublicKey(env->key, &sp); /* modifies sp */ *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"); tor_free(*out); - tor_free(s); return -1; } - tor_free(s); - return len; + /* Remove spaces */ + 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; - RSA *rsa; + char buf1[PK_BYTES*2 + PK_BYTES/64 + 2]; + char buf[PK_BYTES*2]; int len; - tor_assert(env && in); + int i; + tor_assert(in); len = strlen(in); - buf = bufp = tor_malloc(len+1); - if (base64_decode(buf, len+1, in, len)<0) { - tor_free(buf); + + if (strlen(in) > PK_BYTES*2) { + return NULL; + } + /* base64_decode doesn't work unless we insert linebreaks every 64 + * characters. how dumb. */ + for(i=0;i*64<len;i+=1) { + strncpy(buf1+(64+1)*i, in+64*i, 64); + strcpy(buf1+(64+1)*i + 64, "\n"); + } + len = base64_decode(buf, sizeof(buf), buf1, strlen(buf1)); + if (len<0) { log_fn(LOG_WARN,"Error base-64 decoding key"); - return -1; + return NULL; } - rsa = d2i_RSAPublicKey(NULL, &bufp, strlen(buf)); - tor_free(buf); - if (!rsa) - return -1; - if (env->key) RSA_free(env->key); - env->key = rsa; - return 0; + return crypto_pk_asn1_decode(buf, len); } /** Return true iff <b>env</b> has a valid key. diff --git a/src/common/crypto.h b/src/common/crypto.h index 699e4ad2a..6d1e230b2 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -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_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_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); crypto_pk_env_t *crypto_pk_dup_key(crypto_pk_env_t *orig); diff --git a/src/common/util.h b/src/common/util.h index 9c68fba97..11b9b1336 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -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) void tor_strlower(char *s); 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 * that isn't aligned to a word boundary. The macros and/or functions diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 0ff8959ec..a9e37c707 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -557,7 +557,7 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen, char signature[128]; char published[33]; time_t published_on; - int i, identity_pkeylen; + int i; eos = s+maxlen; if (!descriptor_list) @@ -565,14 +565,15 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen, if (list_running_servers(&cp)) return -1; -#if 0 - /* PEM-encode the identity key key */ - if(crypto_pk_write_public_key_to_string(private_key, - &identity_pkey,&identity_pkeylen)<0) { + + /* ASN.1-encode the public key. This is a temporary measure; once + * everyone is running 0.0.9pre3 or later, we can shift to using a + * 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!"); return -1; } -#endif dirserv_remove_old_servers(ROUTER_MAX_AGE); published_on = time(NULL); format_iso_time(published, published_on); @@ -580,8 +581,9 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen, "signed-directory\n" "published %s\n" "recommended-software %s\n" - "running-routers %s\n\n", - published, options.RecommendedVersions, cp); + "running-routers %s\n" + "opt dir-signing-key %s\n\n", + published, options.RecommendedVersions, cp, identity_pkey); tor_free(cp); tor_free(identity_pkey); diff --git a/src/or/test.c b/src/or/test.c index 800ad72cb..48a30cec6 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -365,6 +365,20 @@ test_crypto() 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_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(pk2)); @@ -1095,6 +1109,7 @@ main(int c, char**v){ // puts("========================== Buffers ========================="); // test_buffers(); puts("\n========================== Crypto =========================="); + // add_stream_log(LOG_DEBUG, LOG_ERR, "<stdout>", stdout); test_crypto(); test_crypto_dh(); puts("\n========================= Util ============================"); @@ -1105,7 +1120,6 @@ main(int c, char**v){ test_onion(); test_onion_handshake(); puts("\n========================= Directory Formats ==============="); - /* add_stream_log(LOG_DEBUG, LOG_ERR, "<stdout>", stdout); */ test_dir_format(); puts("\n========================= Rendezvous functionality ========"); test_rend_fns(); |