static crypto_error_t crypto_pad(bytestring_t *dst, const bytestring_t *ctx,const bytestring_t *src)
{
    unsigned char e;

    bytestring_copy(dst,src);

    bytestring_get_element(&e,ctx,1);
    switch (((unsigned)e)<<8)
    {
        case CRYPTO_PAD_OPT_80_ZERO:
            if ((bytestring_get_size(dst)&0x7)==0)
                break;
        case CRYPTO_PAD_ISO9797_P2:
            bytestring_pushback(dst,0x80);
            bytestring_pad_right(dst,8,0);
            break;
        case CRYPTO_PAD_ZERO:
            bytestring_pad_right(dst,8,0);
            break;
        default:
            bytestring_clear(dst);
            return CRYPTO_ERROR_UNKNOWN_PADDING_METHOD;
    }
    return CRYPTO_OK;
}
static int verify_signature(const bytestring_t *source, const bytestring_t *signature)
{
    static const char *pubkey_value = CARDPEEK_PUBLIC_KEY;
    BIO *bp;
    RSA* pubkey;
    int retval;
    unsigned char digest[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;

    if ((bp = BIO_new_mem_buf((void*)pubkey_value,strlen(pubkey_value)))==NULL)
    {
        log_printf(LOG_ERROR,"Failed to build BIO for memory object");
        return 0;
    }

    if ((pubkey = PEM_read_bio_RSA_PUBKEY(bp, NULL, NULL, NULL))==NULL)
    {
        log_printf(LOG_ERROR,"Failed to load public in memory");
        BIO_free(bp);
        return 0;
    }
    BIO_free(bp);

    SHA256_Init(&sha256);
    SHA256_Update(&sha256,bytestring_get_data(source),bytestring_get_size(source));
    SHA256_Final(digest,&sha256);

    retval= RSA_verify(NID_sha256,
            digest,
            SHA256_DIGEST_LENGTH,
            (unsigned char *)bytestring_get_data(signature),
            bytestring_get_size(signature),
            pubkey);

    if (retval==0)
    {
        log_printf(LOG_ERROR,
                   "Signature verification failed for update information (%s)\n",
                   ERR_error_string(ERR_get_error(),NULL));
    }

    RSA_free(pubkey);

    return retval;
}
crypto_error_t crypto_create_context(bytestring_t *ctx,
                                     crypto_alg_t alg_type,
                                     const bytestring_t *key_bin)
{
    DES_key_schedule ks;

    bytestring_clear(ctx);
    bytestring_pushback(ctx,ALG_TYPE(alg_type));
    bytestring_pushback(ctx,PAD_TYPE(alg_type)>>8);

    switch (ALG_TYPE(alg_type))
    {
        case CRYPTO_ALG_DES_ECB:
        case CRYPTO_ALG_DES_CBC:
            if (key_bin==NULL || bytestring_get_size(key_bin)!=8 || key_bin->width!=8)
                return CRYPTO_ERROR_BAD_KEY_FORMAT;

            DES_set_key_unchecked((const_DES_cblock *)key_bin->data,&ks);
            bytestring_append_data(ctx,DES_KS_SIZE,(unsigned char *)&ks);

            break;

        case CRYPTO_ALG_DES2_EDE_ECB:
        case CRYPTO_ALG_DES2_EDE_CBC:
        case CRYPTO_ALG_ISO9797_M3:

            if (key_bin==NULL || bytestring_get_size(key_bin)!=16 || key_bin->width!=8)
                return CRYPTO_ERROR_BAD_KEY_FORMAT;

            DES_set_key_unchecked((const_DES_cblock *)key_bin->data,&ks);
            bytestring_append_data(ctx,DES_KS_SIZE,(unsigned char *)&ks);

            DES_set_key_unchecked((const_DES_cblock *)(key_bin->data+8),&ks);
            bytestring_append_data(ctx,DES_KS_SIZE,(unsigned char *)&ks);

            break;
        case CRYPTO_ALG_SHA1:
            /* nothing else to do */
            break;
        default:
            return CRYPTO_ERROR_UNKNOWN_KEY_TYPE;
    }
    return CRYPTO_OK;
}
crypto_error_t crypto_mac(bytestring_t *dst,
                          const bytestring_t *ctx,
                          const bytestring_t *src)
{
    unsigned u,v;
    unsigned char tmp[8];
    unsigned char clr[8];
    unsigned char alg;
    crypto_error_t retval;
    bytestring_t *padded_src;
    DES_key_schedule key_schedule;
    DES_key_schedule key_schedule2;

    bytestring_get_element(&alg,ctx,0);

    if (alg==CRYPTO_ALG_ISO9797_M3)
    {
        padded_src = bytestring_new(8);
        retval = crypto_pad(padded_src,ctx,src);
        if (retval!=CRYPTO_OK)
        {
            bytestring_free(padded_src);
            return retval;
        }
        memset(tmp,0,8);

        memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE);
        memcpy(&key_schedule2,ctx->data+KS_HEADER_SIZE+DES_KS_SIZE,DES_KS_SIZE);

        for (u=0; u<bytestring_get_size(padded_src)/8; u++)
        {
            for (v=0; v<8; v++) clr[v]=padded_src->data[u*8+v]^tmp[v];
            DES_ecb_encrypt((const_DES_cblock *)clr,
                            (DES_cblock *)tmp,
                            &key_schedule,
                            DES_ENCRYPT);
        }
        memcpy(clr,tmp,8);
        DES_ecb_encrypt((const_DES_cblock *)clr,
                        (DES_cblock *)tmp,
                        &key_schedule2,
                        DES_DECRYPT);
        memcpy(clr,tmp,8);
        DES_ecb_encrypt((const_DES_cblock *)clr,
                        (DES_cblock *)tmp,
                        &key_schedule,
                        DES_ENCRYPT);
        bytestring_assign_data(dst,8,tmp);
        bytestring_free(padded_src);
    }
    else
        return CRYPTO_ERROR_UNKNOWN_ALGORITHM;
    return CRYPTO_OK;
}
Exemple #5
0
const bytestring_t *cardreader_last_atr(cardreader_t *reader)
{
  const bytestring_t *atr = reader->last_atr(reader);
  char *tmp;

  if (atr)
  {
	tmp = bytestring_to_format("%D",atr);
        log_printf(LOG_INFO,"ATR is %i bytes: %s",bytestring_get_size(atr),tmp);
        free(tmp);
  }
  return atr;
}
crypto_error_t crypto_digest(bytestring_t *dst,
                             const bytestring_t *ctx,
                             const bytestring_t *src)
{
    unsigned char alg;

    bytestring_get_element(&alg,ctx,0);

    if (alg==CRYPTO_ALG_SHA1)
    {
        bytestring_resize(dst,SHA_DIGEST_LENGTH);
        SHA1(src->data,bytestring_get_size(src),dst->data);
    }
    else
        return CRYPTO_ERROR_UNKNOWN_ALGORITHM;
    return CRYPTO_OK;
}
crypto_error_t crypto_encrypt(bytestring_t *dst,
                              const bytestring_t *ctx,
                              const bytestring_t *src,
                              const bytestring_t *iv)
{
    unsigned pad_type;
    bytestring_t *padded_src;
    crypto_error_t retval;

    bytestring_get_element((unsigned char *)&pad_type,ctx,1);

    if (pad_type==0 && (bytestring_get_size(src)&0x7)==0)
        return crypto_cipher(dst,ctx,src,iv,DES_ENCRYPT);

    padded_src=bytestring_new(8);
    retval = crypto_pad(padded_src,ctx,src);
    if (retval==CRYPTO_OK)
    {
        retval = crypto_cipher(dst,ctx,padded_src,iv,DES_ENCRYPT);
    }
    bytestring_free(padded_src);
    return retval;
}
static const char* hex_pretty_print(int indent, const bytestring_t *bs,int add_ascii)
{
  static char retval[1500];
  int i;
  int offset;
  int line;
  int sizebs=bytestring_get_size(bs);
  int linesize=indent+48+4+16+1;
  unsigned char e;

  if (sizebs==0)
    return "(nil)\n";

  for (i=0;i<sizebs;i++)
  {
    offset = (i&0x0F);
    line = (i&0xFFF0)>>4;
    if (offset==0)
    {
      memset(retval+line*linesize,' ',linesize);
      retval[line*linesize+linesize-1]='\n';
      retval[line*linesize+linesize]=0;
    }
    bytestring_get_element(&e,bs,i);
    retval[line*linesize+indent+offset*3]=HEX_CHAR[(e>>4)];
    retval[line*linesize+indent+offset*3+1]=HEX_CHAR[e&0xF];
    if (add_ascii)
    {
      if (e>=' ' && e<=126)
	retval[line*linesize+indent+52+offset]=e;
      else
	retval[line*linesize+indent+52+offset]='.';
    }
  }
  return retval+indent;
}
/*
static void update_dump(update_t *update, FILE* out)
{
    update_item_t *item = update->items;

    fprintf(out,"Update version %s\n",update->update_version);
    while (item)
    {
        update_item_dump(item,out);
        item = item->next;
    }
}
*/
static int update_load(update_t *update, const char *data, unsigned data_len)
{
    char *ptr = (char *)data;
    unsigned ptr_len = data_len;
    char *data_end;
    char *value;
    update_item_t *item = NULL;
    bytestring_t *signature;
    bytestring_t *source;
    int signature_verified;

#define fail_update(m) { log_printf(LOG_ERROR,"Failed to parse update information: %s",m); \
                         goto update_new_fail; }


    if ((value = tokenizer_get_record(&ptr,&ptr_len))==NULL) fail_update("Missing header");
    if (strcmp(value,"header")!=0) fail_update("Incorrect header");
    g_free(value);
    
    if ((value = tokenizer_get_field("version",&ptr,&ptr_len))==NULL) fail_update("missing version");
    update->update_version = value; /* don't free value */

    data_end = ptr;
    while ((value = tokenizer_get_record(&ptr,&ptr_len))!=NULL)
    {
        if (strcmp(value,"update")!=0) break;
        g_free(value);

        item = update_item_new();

        if ((value = tokenizer_get_field("file",&ptr,&ptr_len))==NULL) 
            fail_update("missing file name");
        item->file = value;

        if ((value = tokenizer_get_field("url",&ptr,&ptr_len))==NULL) 
            fail_update("missing url");
        item->url = value;

        if ((value = tokenizer_get_field("required_version",&ptr,&ptr_len))==NULL) 
            fail_update("missing required version");
        item->required_version = value;

        if ((value = tokenizer_get_field("digest",&ptr,&ptr_len))==NULL) 
            fail_update("missing digest");
        bytestring_assign_digit_string(&item->digest,value);
        g_free(value);

        if (bytestring_get_size(&item->digest)!=SHA256_DIGEST_LENGTH) 
            fail_update("incorrect digest length");

        if ((value = tokenizer_get_field("message",&ptr,&ptr_len))==NULL)
            fail_update("missing message");
        item->message = value;

        update->item_count++;
        item->next = update->items;
        update->items = item;
        item = NULL;
        data_end = ptr;
    }
    if (value==NULL) 
        fail_update("missing section");
    if (strcmp(value,"authentication")!=0) 
        fail_update("missing authentication");
    g_free(value);

    if ((value = tokenizer_get_field("signature",&ptr,&ptr_len))==NULL) 
        fail_update("missing signature");

    signature = bytestring_new(8);
    bytestring_assign_digit_string(signature,value);
    g_free(value);

    log_printf(LOG_DEBUG,"Verifying %d bit signature on update information (%d bytes), representing %d files.",
               bytestring_get_size(signature)*8,data_end-data,update->item_count);


    source =  bytestring_new(8);
    bytestring_assign_data(source,data_end-data,(const unsigned char *)data);

    if (verify_signature(source,signature)==0)
    {
        log_printf(LOG_ERROR,"Signature verification failed on update information.");
        signature_verified = 0;
        update_clear(update);
    }
    else
    {
        log_printf(LOG_INFO,"Signature verification succeeded on update information.");
        signature_verified = 1;
    }

    bytestring_free(signature);
    bytestring_free(source);
  
    return signature_verified;

update_new_fail:
    if (value) g_free(value);
    if (update) update_clear(update);
    if (item) update_item_free(item);
    return 0;
}
static unsigned short pcsc_transmit(cardreader_t* cr,
                                    const bytestring_t* command,
                                    bytestring_t* result)
{
    pcsc_data_t* pcsc = cr->extra_data;
    BYTE REC_DAT[MAX_PCSC_READ_LENGTH];
    DWORD REC_LEN=MAX_PCSC_READ_LENGTH;
    unsigned short SW;

    if (cr->protocol==SCARD_PROTOCOL_T0)
    {
        pcsc->status = SCardTransmit(pcsc->hcard,SCARD_PCI_T0,
                bytestring_get_data(command),
                bytestring_get_size(command),
                SCARD_PCI_NULL,
                REC_DAT,&REC_LEN);
    }
    else if (cr->protocol==SCARD_PROTOCOL_T1)
    {
        pcsc->status = SCardTransmit(pcsc->hcard,SCARD_PCI_T1,
                bytestring_get_data(command),
                bytestring_get_size(command),
                SCARD_PCI_NULL,
                REC_DAT,&REC_LEN);

    }
    else
    {
        log_printf(LOG_ERROR,"Unknown smartcard protocol: %i",cr->protocol);
        return CARDPEEK_ERROR_SW;
    }

    if (pcsc->status!=SCARD_S_SUCCESS)
    {
        log_printf(LOG_ERROR,"Failed to transmit command to card: %s (error 0x%08x).",
                pcsc_stringify_error(pcsc->status),
                pcsc->status );
        return CARDPEEK_ERROR_SW;
    }

    if (REC_LEN>=2)
    {
        bytestring_assign_data(result,REC_LEN-2,REC_DAT);
        SW = (REC_DAT[REC_LEN-2]<<8)|REC_DAT[REC_LEN-1];
    }
    else if (REC_LEN==1)
    {
        bytestring_clear(result);
        SW = REC_DAT[0];
    }
    else
    {
        log_printf(LOG_ERROR,"Transmited %i bytes to the card (%s), but recieved a response of length %i, without any status word included.",
                bytestring_get_size(command),
                pcsc_stringify_protocol(cr->protocol),
                REC_LEN);
        return CARDPEEK_ERROR_SW;
    }

    return SW;
}
static crypto_error_t crypto_cipher(bytestring_t *dst,
                                    const bytestring_t *ctx,
                                    const bytestring_t *src,
                                    const bytestring_t *iv,
                                    int enc)
{
    unsigned u;
    unsigned char alg;
    DES_key_schedule key_schedule;
    DES_key_schedule key_schedule2;

    if (bytestring_get_element(&alg,ctx,0)!=BYTESTRING_OK)
        return CRYPTO_ERROR_UNKNOWN;

    if ((bytestring_get_size(src)&0x7)!=0)
        return CRYPTO_ERROR_BAD_CLEARTEXT_LENGTH;

    switch (alg)
    {
        case CRYPTO_ALG_DES_ECB:
            bytestring_resize(dst,bytestring_get_size(src));

            memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE);

            for (u=0; u<bytestring_get_size(src)/8; u++)
                DES_ecb_encrypt((const_DES_cblock *)(src->data+u*8),
                                (DES_cblock *)(dst->data+u*8),
                                &key_schedule,
                                enc);
            break;
        case CRYPTO_ALG_DES_CBC:
            if (iv==NULL || bytestring_get_size(iv)!=8)
                return CRYPTO_ERROR_BAD_IV_LENGTH;

            bytestring_resize(dst,bytestring_get_size(src));

            memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE);
            
            DES_ncbc_encrypt(src->data,
                             dst->data,
                             bytestring_get_size(src),
                             &key_schedule,
                             (DES_cblock *)(iv->data),
                             enc);
            break;
        case CRYPTO_ALG_DES2_EDE_ECB:
            bytestring_resize(dst,bytestring_get_size(src));

            memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE);
            memcpy(&key_schedule2,ctx->data+KS_HEADER_SIZE+DES_KS_SIZE,DES_KS_SIZE);
            
            for (u=0; u<bytestring_get_size(src)/8; u++)
                DES_ecb2_encrypt((const_DES_cblock *)(src->data+u*8),
                                 (DES_cblock *)(dst->data+u*8),
                                 &key_schedule,
                                 &key_schedule2,
                                 enc);
            break;
        case CRYPTO_ALG_DES2_EDE_CBC:
            if (iv==NULL || bytestring_get_size(iv)!=8)
                return CRYPTO_ERROR_BAD_IV_LENGTH;

            bytestring_resize(dst,bytestring_get_size(src));


            memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE);
            memcpy(&key_schedule2,ctx->data+KS_HEADER_SIZE+DES_KS_SIZE,DES_KS_SIZE);

            DES_ede2_cbc_encrypt(src->data,
                                 dst->data,
                                 bytestring_get_size(src),
                                 &key_schedule,
                                 &key_schedule2,
                                 (DES_cblock *)(iv->data),
                                 enc);
            break;
        default:
            return CRYPTO_ERROR_UNKNOWN_ALGORITHM;
    }
    return CRYPTO_OK;
}