From 5432755319f34010f587dae19ae325020bf9454c Mon Sep 17 00:00:00 2001 From: David Shaw Date: Mon, 19 Dec 2005 19:39:32 +0000 Subject: [PATCH] * ksutil.h, ksutil.c (curl_armor_writer, curl_writer, curl_writer_finalize): New functionality to handle binary format keys by armoring them for input to GPG. * gpgkeys_curl.c (get_key), gpgkeys_hkp.c (get_key): Call it here. --- keyserver/ChangeLog | 8 ++ keyserver/gpgkeys_curl.c | 17 ++-- keyserver/gpgkeys_hkp.c | 11 +-- keyserver/ksutil.c | 162 ++++++++++++++++++++++++++++++--------- keyserver/ksutil.h | 14 +++- 5 files changed, 165 insertions(+), 47 deletions(-) diff --git a/keyserver/ChangeLog b/keyserver/ChangeLog index f5c720cb9..6ce2c7332 100644 --- a/keyserver/ChangeLog +++ b/keyserver/ChangeLog @@ -1,3 +1,11 @@ +2005-12-19 David Shaw + + * ksutil.h, ksutil.c (curl_armor_writer, curl_writer, + curl_writer_finalize): New functionality to handle binary format + keys by armoring them for input to GPG. + + * gpgkeys_curl.c (get_key), gpgkeys_hkp.c (get_key): Call it here. + 2005-12-07 David Shaw * gpgkeys_finger.c (get_key), gpgkeys_curl.c (get_key): Better diff --git a/keyserver/gpgkeys_curl.c b/keyserver/gpgkeys_curl.c index 10e44a156..bd26d7849 100644 --- a/keyserver/gpgkeys_curl.c +++ b/keyserver/gpgkeys_curl.c @@ -74,13 +74,18 @@ get_key(char *getkey) res,errorbuffer); fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res)); } - else if(!ctx.done) - { - fprintf(console,"gpgkeys: no key data found for %s\n",request); - fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,KEYSERVER_KEY_NOT_FOUND); - } else - fprintf(output,"\nKEY 0x%s END\n",getkey); + { + curl_writer_finalize(&ctx); + if(!ctx.flags.done) + { + fprintf(console,"gpgkeys: no key data found for %s\n",request); + fprintf(output,"\nKEY 0x%s FAILED %d\n", + getkey,KEYSERVER_KEY_NOT_FOUND); + } + else + fprintf(output,"\nKEY 0x%s END\n",getkey); + } return curl_err_to_gpg_err(res); } diff --git a/keyserver/gpgkeys_hkp.c b/keyserver/gpgkeys_hkp.c index 38e9cefde..d51c659ff 100644 --- a/keyserver/gpgkeys_hkp.c +++ b/keyserver/gpgkeys_hkp.c @@ -263,21 +263,22 @@ get_key(char *getkey) curl_easy_setopt(curl,CURLOPT_FILE,&ctx); res=curl_easy_perform(curl); - if(res!=0) + if(res!=CURLE_OK) { fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer); fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res)); } else { - if(ctx.done) - fprintf(output,"\nKEY 0x%s END\n",getkey); - else + curl_writer_finalize(&ctx); + if(!ctx.flags.done) { fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey); - fprintf(output,"KEY 0x%s FAILED %d\n", + fprintf(output,"\nKEY 0x%s FAILED %d\n", getkey,KEYSERVER_KEY_NOT_FOUND); } + else + fprintf(output,"\nKEY 0x%s END\n",getkey); } return KEYSERVER_OK; diff --git a/keyserver/ksutil.c b/keyserver/ksutil.c index e858bd410..8ea2a1ab4 100644 --- a/keyserver/ksutil.c +++ b/keyserver/ksutil.c @@ -371,6 +371,47 @@ curl_err_to_gpg_err(CURLcode error) } } +#define B64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +static void +curl_armor_writer(const unsigned char *buf,size_t size,void *cw_ctx) +{ + struct curl_writer_ctx *ctx=cw_ctx; + size_t idx=0; + + while(idxarmor_remaining<3 && idxarmor_remaining++,idx++) + ctx->armor_ctx[ctx->armor_remaining]=buf[idx]; + + if(ctx->armor_remaining==3) + { + /* Top 6 bytes of ctx->armor_ctx[0] */ + fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream); + /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of + ctx->armor_ctx[1] */ + fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30) + |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream); + /* Bottom 4 bytes of ctx->armor_ctx[1] and top 2 bytes of + ctx->armor_ctx[2] */ + fputc(B64[(((ctx->armor_ctx[1]<<2)&0x3C) + |((ctx->armor_ctx[2]>>6)&0x03))&0x3F],ctx->stream); + /* Bottom 6 bytes of ctx->armor_ctx[2] */ + fputc(B64[(ctx->armor_ctx[2]&0x3F)],ctx->stream); + + ctx->linelen+=4; + if(ctx->linelen>=70) + { + fputc('\n',ctx->stream); + ctx->linelen=0; + } + + ctx->armor_remaining=0; + } + } + +} + size_t curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx) { @@ -378,52 +419,103 @@ curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx) const char *buf=ptr; size_t i; - if(!ctx->initialized) + if(!ctx->flags.initialized) { - ctx->marker=BEGIN; - ctx->initialized=1; - } + if(size*nmemb==0) + return 0; - /* scan the incoming data for our marker */ - for(i=0;!ctx->done && i<(size*nmemb);i++) - { - if(buf[i]==ctx->marker[ctx->markeridx]) + /* The object we're fetching is in binary form */ + if(*buf&0x80) { - ctx->markeridx++; - if(ctx->marker[ctx->markeridx]=='\0') - { - if(ctx->begun) - ctx->done=1; - else - { - /* We've found the BEGIN marker, so now we're looking - for the END marker. */ - ctx->begun=1; - ctx->marker=END; - ctx->markeridx=0; - fprintf(ctx->stream,BEGIN); - continue; - } - } + ctx->flags.armor=1; + fprintf(ctx->stream,BEGIN"\n\n"); } else - ctx->markeridx=0; + ctx->marker=BEGIN; - if(ctx->begun) + ctx->flags.initialized=1; + } + + if(ctx->flags.armor) + curl_armor_writer(ptr,size*nmemb,cw_ctx); + else + { + /* scan the incoming data for our marker */ + for(i=0;!ctx->flags.done && i<(size*nmemb);i++) { - /* Canonicalize CRLF to just LF by stripping CRs. This - actually makes sense, since on Unix-like machines LF is - correct, and on win32-like machines, our output buffer is - opened in textmode and will re-canonicalize line endings - back to CRLF. Since we only need to handle armored keys, - we don't have to worry about odd cases like CRCRCR and - the like. */ + if(buf[i]==ctx->marker[ctx->markeridx]) + { + ctx->markeridx++; + if(ctx->marker[ctx->markeridx]=='\0') + { + if(ctx->flags.begun) + ctx->flags.done=1; + else + { + /* We've found the BEGIN marker, so now we're + looking for the END marker. */ + ctx->flags.begun=1; + ctx->marker=END; + ctx->markeridx=0; + fprintf(ctx->stream,BEGIN); + continue; + } + } + } + else + ctx->markeridx=0; - if(buf[i]!='\r') - fputc(buf[i],ctx->stream); + if(ctx->flags.begun) + { + /* Canonicalize CRLF to just LF by stripping CRs. This + actually makes sense, since on Unix-like machines LF + is correct, and on win32-like machines, our output + buffer is opened in textmode and will re-canonicalize + line endings back to CRLF. Since this code is just + for handling armored keys, we don't have to worry + about odd cases like CRCRCR and the like. */ + + if(buf[i]!='\r') + fputc(buf[i],ctx->stream); + } } } return size*nmemb; } + +void +curl_writer_finalize(struct curl_writer_ctx *ctx) +{ + if(ctx->flags.armor) + { + if(ctx->armor_remaining==2) + { + /* Top 6 bytes of ctx->armorctx[0] */ + fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream); + /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of + ctx->armor_ctx[1] */ + fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30) + |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream); + /* Bottom 4 bytes of ctx->armor_ctx[1] */ + fputc(B64[((ctx->armor_ctx[1]<<2)&0x3C)],ctx->stream); + /* Pad */ + fputc('=',ctx->stream); + } + else if(ctx->armor_remaining==1) + { + /* Top 6 bytes of ctx->armor_ctx[0] */ + fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream); + /* Bottom 2 bytes of ctx->armor_ctx[0] */ + fputc(B64[((ctx->armor_ctx[0]<<4)&0x30)],ctx->stream); + /* Pad */ + fputc('=',ctx->stream); + /* Pad */ + fputc('=',ctx->stream); + } + + fprintf(ctx->stream,"\n"END); + ctx->flags.done=1; + } +} #endif diff --git a/keyserver/ksutil.h b/keyserver/ksutil.h index 8e00e7902..4dd60a7aa 100644 --- a/keyserver/ksutil.h +++ b/keyserver/ksutil.h @@ -111,12 +111,24 @@ int curl_err_to_gpg_err(CURLcode error); struct curl_writer_ctx { - int initialized,markeridx,begun,done; + struct + { + unsigned int initialized:1; + unsigned int begun:1; + unsigned int done:1; + unsigned int armor:1; + } flags; + + int armor_remaining; + unsigned char armor_ctx[3]; + int markeridx,linelen; const char *marker; FILE *stream; }; size_t curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx); +void curl_writer_finalize(struct curl_writer_ctx *ctx); + #endif #endif /* !_KSUTIL_H_ */