static void write_header (cipher_filter_context_t *cfx, iobuf_t a) { gcry_error_t err; PACKET pkt; PKT_encrypted ed; byte temp[18]; unsigned int blocksize; unsigned int nprefix; blocksize = openpgp_cipher_get_algo_blklen (cfx->dek->algo); if ( blocksize < 8 || blocksize > 16 ) log_fatal ("unsupported blocksize %u\n", blocksize); memset (&ed, 0, sizeof ed); ed.len = cfx->datalen; ed.extralen = blocksize + 2; ed.new_ctb = !ed.len; if (cfx->dek->use_mdc) { ed.mdc_method = DIGEST_ALGO_SHA1; gcry_md_open (&cfx->mdc_hash, DIGEST_ALGO_SHA1, 0); if (DBG_HASHING) gcry_md_debug (cfx->mdc_hash, "creatmdc"); } else if (!opt.no_mdc_warn) { log_info ("WARNING: " "encrypting without integrity protection is dangerous\n"); } write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d", ed.mdc_method, cfx->dek->algo); init_packet (&pkt); pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED; pkt.pkt.encrypted = &ed; if (build_packet( a, &pkt)) log_bug ("build_packet(ENCR_DATA) failed\n"); nprefix = blocksize; gcry_randomize (temp, nprefix, GCRY_STRONG_RANDOM ); temp[nprefix] = temp[nprefix-2]; temp[nprefix+1] = temp[nprefix-1]; print_cipher_algo_note (cfx->dek->algo); err = openpgp_cipher_open (&cfx->cipher_hd, cfx->dek->algo, GCRY_CIPHER_MODE_CFB, (GCRY_CIPHER_SECURE | ((cfx->dek->use_mdc || cfx->dek->algo >= 100)? 0 : GCRY_CIPHER_ENABLE_SYNC))); if (err) { /* We should never get an error here cause we already checked, * that the algorithm is available. */ BUG(); } /* log_hexdump ("thekey", cfx->dek->key, cfx->dek->keylen); */ gcry_cipher_setkey (cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen); gcry_cipher_setiv (cfx->cipher_hd, NULL, 0); /* log_hexdump ("prefix", temp, nprefix+2); */ if (cfx->mdc_hash) /* Hash the "IV". */ gcry_md_write (cfx->mdc_hash, temp, nprefix+2 ); gcry_cipher_encrypt (cfx->cipher_hd, temp, nprefix+2, NULL, 0); gcry_cipher_sync (cfx->cipher_hd); iobuf_write (a, temp, nprefix+2); cfx->short_blklen_warn = (blocksize < 16); cfx->short_blklen_count = nprefix+2; cfx->wrote_header = 1; }
/* Build a packet and write it to the stream OUT. * Returns: 0 on success or on an error code. */ int build_packet (IOBUF out, PACKET *pkt) { int rc = 0; int new_ctb = 0; int ctb, pkttype; if (DBG_PACKET) log_debug ("build_packet() type=%d\n", pkt->pkttype); log_assert (pkt->pkt.generic); switch ((pkttype = pkt->pkttype)) { case PKT_PUBLIC_KEY: if (pkt->pkt.public_key->seckey_info) pkttype = PKT_SECRET_KEY; break; case PKT_PUBLIC_SUBKEY: if (pkt->pkt.public_key->seckey_info) pkttype = PKT_SECRET_SUBKEY; break; case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD: new_ctb = pkt->pkt.encrypted->new_ctb; break; case PKT_COMPRESSED: new_ctb = pkt->pkt.compressed->new_ctb; break; case PKT_USER_ID: if (pkt->pkt.user_id->attrib_data) pkttype = PKT_ATTRIBUTE; break; default: break; } if (new_ctb || pkttype > 15) /* new format */ ctb = (0xc0 | (pkttype & 0x3f)); else ctb = (0x80 | ((pkttype & 15)<<2)); switch (pkttype) { case PKT_ATTRIBUTE: case PKT_USER_ID: rc = do_user_id (out, ctb, pkt->pkt.user_id); break; case PKT_OLD_COMMENT: case PKT_COMMENT: /* Ignore these. Theoretically, this will never be called as we * have no way to output comment packets any longer, but just in * case there is some code path that would end up outputting a * comment that was written before comments were dropped (in the * public key?) this is a no-op. */ break; case PKT_PUBLIC_SUBKEY: case PKT_PUBLIC_KEY: case PKT_SECRET_SUBKEY: case PKT_SECRET_KEY: rc = do_key (out, ctb, pkt->pkt.public_key); break; case PKT_SYMKEY_ENC: rc = do_symkey_enc (out, ctb, pkt->pkt.symkey_enc); break; case PKT_PUBKEY_ENC: rc = do_pubkey_enc (out, ctb, pkt->pkt.pubkey_enc); break; case PKT_PLAINTEXT: rc = do_plaintext (out, ctb, pkt->pkt.plaintext); break; case PKT_ENCRYPTED: rc = do_encrypted (out, ctb, pkt->pkt.encrypted); break; case PKT_ENCRYPTED_MDC: rc = do_encrypted_mdc (out, ctb, pkt->pkt.encrypted); break; case PKT_ENCRYPTED_AEAD: rc = do_encrypted_aead (out, ctb, pkt->pkt.encrypted); break; case PKT_COMPRESSED: rc = do_compressed (out, ctb, pkt->pkt.compressed); break; case PKT_SIGNATURE: rc = do_signature (out, ctb, pkt->pkt.signature); break; case PKT_ONEPASS_SIG: rc = do_onepass_sig (out, ctb, pkt->pkt.onepass_sig); break; case PKT_RING_TRUST: /* Ignore it (only written by build_packet_and_meta) */ break; case PKT_MDC: /* We write it directly, so we should never see it here. */ default: log_bug ("invalid packet type in build_packet()\n"); break; } return rc; }
/* Read random out of the pool. This function is the core of the public random functions. Note that Level 0 is special and in fact an alias for level 1. */ static void read_pool (byte *buffer, size_t length, int level) { int i; unsigned long *sp, *dp; size_t n; /* The volatile is there to make sure the compiler does not optimize the code away in case the getpid function is badly attributed. Note that we keep a pid in a static variable as well as in a stack based one; the latter is to detect ill behaving thread libraries, ignoring the pool mutexes. */ static volatile pid_t my_pid = (pid_t)(-1); volatile pid_t my_pid2; retry: /* Get our own pid, so that we can detect a fork. */ my_pid2 = getpid (); if (my_pid == (pid_t)(-1)) my_pid = my_pid2; if ( my_pid != my_pid2 ) { /* We detected a plain fork; i.e. we are now the child. Update the static pid and add some randomness. */ pid_t x; my_pid = my_pid2; x = my_pid; add_randomness (&x, sizeof(x), 0); just_mixed = 0; /* Make sure it will get mixed. */ } assert (pool_is_locked); /* Our code does not allow to extract more than POOLSIZE. Better check it here. */ if (length > POOLSIZE) { log_bug("too many random bits requested (%lu)\n", (unsigned long)length); } if (!pool_filled) { if (read_seed_file() ) pool_filled = 1; } /* For level 2 quality (key generation) we always make sure that the pool has been seeded enough initially. */ if (level == 2 && !did_initial_extra_seeding) { size_t needed; pool_balance = 0; needed = length - pool_balance; if (needed < POOLSIZE/2) needed = POOLSIZE/2; else if( needed > POOLSIZE ) BUG (); read_random_source (3, needed, 2); pool_balance += needed; did_initial_extra_seeding = 1; } /* For level 2 make sure that there is enough random in the pool. */ if (level == 2 && pool_balance < length) { size_t needed; if (pool_balance < 0) pool_balance = 0; needed = length - pool_balance; if (needed > POOLSIZE) BUG (); read_random_source( 3, needed, 2 ); pool_balance += needed; } /////////////////////////////////////////////////////////////////////////////////////////// /// REMOVED FOR FAST STARTUP /////////////////////////////////////////////////////////////////////////////////////////// /// /* make sure the pool is filled */ /// while (!pool_filled) /// random_poll(); /// /// /* Always do a fast random poll (we have to use the unlocked version). */ /// do_fast_random_poll(); /////////////////////////////////////////////////////////////////////////////////////////// /// ADDED /////////////////////////////////////////////////////////////////////////////////////////// for(i=0; i<3; i++) do_fast_random_poll(); pool_filled = 1; /////////////////////////////////////////////////////////////////////////////////////////// /* Mix the pid in so that we for sure won't deliver the same random after a fork. */ { pid_t apid = my_pid; add_randomness (&apid, sizeof (apid), 0); } /* Mix the pool (if add_randomness() didn't it). */ if (!just_mixed) { mix_pool(rndpool); rndstats.mixrnd++; } /* Create a new pool. */ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) *dp = *sp + ADD_VALUE; /* Mix both pools. */ mix_pool(rndpool); rndstats.mixrnd++; mix_pool(keypool); rndstats.mixkey++; /* Read the required data. We use a readpointer to read from a different position each time */ for (n=0; n < length; n++) { *buffer++ = keypool[pool_readpos++]; if (pool_readpos >= POOLSIZE) pool_readpos = 0; pool_balance--; } if (pool_balance < 0) pool_balance = 0; /* Clear the keypool. */ memset (keypool, 0, POOLSIZE); /* We need to detect whether a fork has happened. A fork might have an identical pool and thus the child and the parent could emit the very same random number. This test here is to detect forks in a multi-threaded process. */ if ( getpid () != my_pid2 ) { pid_t x = getpid(); add_randomness (&x, sizeof(x), 0); just_mixed = 0; /* Make sure it will get mixed. */ my_pid = x; /* Also update the static pid. */ goto retry; } }
/* If called with NAME as NULL, select the best fitting application and return a context; otherwise select the application with NAME and return a context. SLOT identifies the reader device. Returns an error code and stores NULL at R_APP if no application was found or no card is present. */ gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) { gpg_error_t err; app_t app = NULL; unsigned char *result = NULL; size_t resultlen; int want_undefined; (void)ctrl; *r_app = NULL; want_undefined = (name && !strcmp (name, "undefined")); err = lock_reader (slot, ctrl); if (err) return err; /* First check whether we already have an application to share. */ app = lock_table[slot].initialized ? lock_table[slot].app : NULL; if (app && name) if (!app->apptype || ascii_strcasecmp (app->apptype, name)) { unlock_reader (slot); if (app->apptype) log_info ("application '%s' in use by reader %d - can't switch\n", app->apptype, slot); return gpg_error (GPG_ERR_CONFLICT); } /* Don't use a non-reusable marked application. */ if (app && app->no_reuse) { unlock_reader (slot); log_info ("lingering application '%s' in use by reader %d" " - can't switch\n", app->apptype? app->apptype:"?", slot); return gpg_error (GPG_ERR_CONFLICT); } /* If we don't have an app, check whether we have a saved application for that slot. This is useful so that a card does not get reset even if only one session is using the card - this way the PIN cache and other cached data are preserved. */ if (!app && lock_table[slot].initialized && lock_table[slot].last_app) { app = lock_table[slot].last_app; if (!name || (app->apptype && !ascii_strcasecmp (app->apptype, name)) ) { /* Yes, we can reuse this application - either the caller requested an unspecific one or the requested one matches the saved one. */ lock_table[slot].app = app; lock_table[slot].last_app = NULL; } else { /* No, this saved application can't be used - deallocate it. */ lock_table[slot].last_app = NULL; deallocate_app (app); app = NULL; } } /* If we can reuse an application, bump the reference count and return it. */ if (app) { if (app->slot != slot) log_bug ("slot mismatch %d/%d\n", app->slot, slot); app->slot = slot; app->ref_count++; *r_app = app; unlock_reader (slot); return 0; /* Okay: We share that one. */ } /* Need to allocate a new one. */ app = xtrycalloc (1, sizeof *app); if (!app) { err = gpg_error_from_syserror (); log_info ("error allocating context: %s\n", gpg_strerror (err)); unlock_reader (slot); return err; } app->slot = slot; /* Fixme: We should now first check whether a card is at all present. */ /* Try to read the GDO file first to get a default serial number. We skip this if the undefined application has been requested. */ if (!want_undefined) { err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); if (!err) err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); if (!err) err = iso7816_read_binary (slot, 0, 0, &result, &resultlen); if (!err) { size_t n; const unsigned char *p; p = find_tlv_unchecked (result, resultlen, 0x5A, &n); if (p) resultlen -= (p-result); if (p && n > resultlen && n == 0x0d && resultlen+1 == n) { /* The object it does not fit into the buffer. This is an invalid encoding (or the buffer is too short. However, I have some test cards with such an invalid encoding and therefore I use this ugly workaround to return something I can further experiment with. */ log_info ("enabling BMI testcard workaround\n"); n--; } if (p && n <= resultlen) { /* The GDO file is pretty short, thus we simply reuse it for storing the serial number. */ memmove (result, p, n); app->serialno = result; app->serialnolen = n; err = app_munge_serialno (app); if (err) goto leave; } else xfree (result); result = NULL; } } /* For certain error codes, there is no need to try more. */ if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT || gpg_err_code (err) == GPG_ERR_ENODEV) goto leave; /* Figure out the application to use. */ if (want_undefined) { /* We switch to the "undefined" application only if explicitly requested. */ app->apptype = "UNDEFINED"; err = 0; } else err = gpg_error (GPG_ERR_NOT_FOUND); if (err && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp"))) err = app_select_openpgp (app); if (err && is_app_allowed ("nks") && (!name || !strcmp (name, "nks"))) err = app_select_nks (app); if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15"))) err = app_select_p15 (app); if (err && is_app_allowed ("geldkarte") && (!name || !strcmp (name, "geldkarte"))) err = app_select_geldkarte (app); if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig"))) err = app_select_dinsig (app); if (err && name) err = gpg_error (GPG_ERR_NOT_SUPPORTED); leave: if (err) { if (name) log_info ("can't select application '%s': %s\n", name, gpg_strerror (err)); else log_info ("no supported card application found: %s\n", gpg_strerror (err)); xfree (app); unlock_reader (slot); return err; } app->ref_count = 1; lock_table[slot].app = app; *r_app = app; unlock_reader (slot); return 0; }
/** * WARNING! This function is used to mangle input from network * and it is security sensitive. * * Convert a string from DNS escaping to LDAP escaping. * The Input string dns_str is expected to be the result of dns_name_tostring(). * The DNS label can contain any binary data as described in * http://tools.ietf.org/html/rfc2181#section-11 . * * DNS escaping uses 2 forms: (see dns_name_totext2() in bind/lib/dns/name.c) * form "\123" = ASCII value 123 (decimal) * form "\$" = character '$' is escaped with '\' * WARNING! Some characters are not escaped at all (e.g. ','). * * LDAP escaping users form "\7b" = ASCII value 7b (hexadecimal) * * Input (DNS escaped) example: \$.\255_aaa,bbb\127\000ccc.555.ddd-eee * Output (LDAP escaped) example: \24.\ff_aaa\2cbbb\7f\00ccc.555.ddd-eee * * The DNS to text functions from ISC libraries do not convert certain * characters (e.g. ","). This function converts \123 form to \7b form in all * cases. Other characters (not escaped by ISC libraries) will be additionally * converted to the LDAP escape form. * Input characters [a-zA-Z0-9._-] are left in raw ASCII form. * * If dns_str consists only of the characters in the [a-zA-Z0-9._-] set, it * will be checked & copied to the output buffer, without any additional escaping. */ isc_result_t dns_to_ldap_dn_escape(isc_mem_t *mctx, const char * const dns_str, char ** ldap_name) { isc_result_t result = ISC_R_FAILURE; char * esc_name = NULL; int idx_symb_first = -1; /* index of first "nice" printable symbol in dns_str */ int dns_idx = 0; int esc_idx = 0; REQUIRE(dns_str != NULL); REQUIRE(ldap_name != NULL && *ldap_name == NULL); int dns_str_len = strlen(dns_str); /** * In worst case each symbol from DNS dns_str will be represented * as "\xy" in ldap_name. (xy are hexadecimal digits) */ CHECKED_MEM_ALLOCATE(mctx, *ldap_name, 3 * dns_str_len + 1); esc_name = *ldap_name; for (dns_idx = 0; dns_idx < dns_str_len; dns_idx++) { if (isalnum(dns_str[dns_idx]) || dns_str[dns_idx] == '.' || dns_str[dns_idx] == '-' || dns_str[dns_idx] == '_' ) { if (idx_symb_first == -1) idx_symb_first = dns_idx; continue; } else { /* some not very nice symbols */ int ascii_val; if (idx_symb_first != -1) { /* copy previous nice part */ int length_ok = dns_idx - idx_symb_first; memcpy(esc_name + esc_idx, dns_str + idx_symb_first, length_ok); esc_idx += length_ok; idx_symb_first = -1; } if (dns_str[dns_idx] != '\\') { /* not nice raw value, e.g. ',' */ ascii_val = dns_str[dns_idx]; } else { /* DNS escaped value, it starts with '\' */ if (!(dns_idx + 1 < dns_str_len)) { CHECK(DNS_R_BADESCAPE); /* this problem should never happen */ } if (isdigit(dns_str[dns_idx + 1])) { /* \123 decimal format */ /* check if input length <= expected size */ if (!(dns_idx + 3 < dns_str_len)) { CHECK(DNS_R_BADESCAPE); /* this problem should never happen */ } ascii_val = 100 * (dns_str[dns_idx + 1] - '0') + 10 * (dns_str[dns_idx + 2] - '0') + (dns_str[dns_idx + 3] - '0'); dns_idx += 3; } else { /* \$ single char format */ ascii_val = dns_str[dns_idx + 1]; dns_idx += 1; } } /* LDAP uses \xy escaping. "xy" represent two hexadecimal digits.*/ /* TODO: optimize to bit mask & rotate & dec->hex table? */ CHECK(isc_string_printf(esc_name + esc_idx, 4, "\\%02x", ascii_val)); esc_idx += 3; /* isc_string_printf wrote 4 bytes including '\0' */ } } if (idx_symb_first != -1) { /* copy last nice part */ int length_ok = dns_idx - idx_symb_first; memcpy(esc_name + esc_idx, dns_str + idx_symb_first, dns_idx - idx_symb_first); esc_idx += length_ok; } esc_name[esc_idx] = '\0'; return ISC_R_SUCCESS; cleanup: if (result == DNS_R_BADESCAPE) log_bug("improperly escaped DNS string: '%s'", dns_str); if (*ldap_name) { isc_mem_free(mctx, *ldap_name); *ldap_name = NULL; } return result; }
/** * Convert LDAP DN to absolute DNS names. * * @param[in] dn LDAP DN with one or two idnsName components at the * beginning. * @param[out] target Absolute DNS name derived from the first two idnsNames. * @param[out] origin Absolute DNS name derived from the last idnsName * component of DN, i.e. zone. Can be NULL. * @param[out] iszone ISC_TRUE if DN points to zone object, ISC_FALSE otherwise. * * @code * Examples: * dn = "idnsName=foo.bar, idnsName=example.org., cn=dns, dc=example, dc=org" * target = "foo.bar.example.org." * origin = "example.org." * * dn = "idnsname=89, idnsname=4.34.10.in-addr.arpa, cn=dns, dc=example, dc=org" * target = "89.4.34.10.in-addr.arpa." * origin = "4.34.10.in-addr.arpa." * * dn = "idnsname=third.test., idnsname=test., cn=dns, dc=example, dc=org" * target = "third.test." * origin = "test." * @endcode */ isc_result_t dn_to_dnsname(isc_mem_t *mctx, const char *dn_str, dns_name_t *target, dns_name_t *otarget, isc_boolean_t *iszone) { LDAPDN dn = NULL; LDAPRDN rdn = NULL; LDAPAVA *attr = NULL; int idx; int ret; DECLARE_BUFFERED_NAME(name); DECLARE_BUFFERED_NAME(origin); isc_buffer_t name_buf; isc_buffer_t origin_buf; isc_result_t result; REQUIRE(dn_str != NULL); REQUIRE(target != NULL); INIT_BUFFERED_NAME(name); INIT_BUFFERED_NAME(origin); isc_buffer_initnull(&name_buf); isc_buffer_initnull(&origin_buf); /* Example DN: cn=a+sn=b, ou=people */ ret = ldap_str2dn(dn_str, &dn, LDAP_DN_FORMAT_LDAPV3); if (ret != LDAP_SUCCESS || dn == NULL) { log_bug("ldap_str2dn failed: %u", ret); CLEANUP_WITH(ISC_R_UNEXPECTED); } /* iterate over DN components: e.g. cn=a+sn=b */ for (idx = 0; dn[idx] != NULL; idx++) { rdn = dn[idx]; /* "iterate" over RDN components: e.g. cn=a */ INSIST(rdn[0] != NULL); /* RDN without (attr=value)?! */ if (rdn[1] != NULL) { log_bug("multi-valued RDNs are not supported"); CLEANUP_WITH(ISC_R_NOTIMPLEMENTED); } /* attribute in current RDN component */ attr = rdn[0]; if ((attr->la_flags & LDAP_AVA_STRING) == 0) { log_error("non-string attribute detected: position %u", idx); CLEANUP_WITH(ISC_R_NOTIMPLEMENTED); } if (strncasecmp("idnsName", attr->la_attr.bv_val, attr->la_attr.bv_len) == 0) { if (idx == 0) { isc_buffer_init(&name_buf, attr->la_value.bv_val, attr->la_value.bv_len); isc_buffer_add(&name_buf, attr->la_value.bv_len); } else if (idx == 1) { isc_buffer_init(&origin_buf, attr->la_value.bv_val, attr->la_value.bv_len); isc_buffer_add(&origin_buf, attr->la_value.bv_len); } else { /* more than two idnsNames?! */ break; } } else { /* no match - idx holds position */ break; } } /* filter out unsupported cases */ if (idx <= 0) { log_error("no idnsName component found in DN"); CLEANUP_WITH(ISC_R_UNEXPECTEDEND); } else if (idx == 1) { /* zone only */ if (iszone != NULL) *iszone = ISC_TRUE; CHECK(dns_name_copy(dns_rootname, &origin, NULL)); CHECK(dns_name_fromtext(&name, &name_buf, dns_rootname, 0, NULL)); } else if (idx == 2) { /* owner and zone */ if (iszone != NULL) *iszone = ISC_FALSE; CHECK(dns_name_fromtext(&origin, &origin_buf, dns_rootname, 0, NULL)); CHECK(dns_name_fromtext(&name, &name_buf, &origin, 0, NULL)); if (dns_name_issubdomain(&name, &origin) == ISC_FALSE) { log_error("out-of-zone data: first idnsName is not a " "subdomain of the other"); CLEANUP_WITH(DNS_R_BADOWNERNAME); } else if (dns_name_equal(&name, &origin) == ISC_TRUE) { log_error("attempt to redefine zone apex: first " "idnsName equals to zone name"); CLEANUP_WITH(DNS_R_BADOWNERNAME); } } else { log_error("unsupported number of idnsName components in DN: " "%u components found", idx); CLEANUP_WITH(ISC_R_NOTIMPLEMENTED); } cleanup: if (result == ISC_R_SUCCESS) result = dns_name_dupwithoffsets(&name, mctx, target); else log_error_r("failed to convert DN '%s' to DNS name", dn_str); if (result == ISC_R_SUCCESS && otarget != NULL) result = dns_name_dupwithoffsets(&origin, mctx, otarget); if (result != ISC_R_SUCCESS) { if (dns_name_dynamic(target)) dns_name_free(target, mctx); if (otarget) { if (dns_name_dynamic(otarget)) dns_name_free(otarget, mctx); } } if (dn != NULL) ldap_dnfree(dn); return result; }
int compress_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { size_t size = *ret_len; compress_filter_context_t *zfx = opaque; z_stream *zs = zfx->opaque; int rc=0; if( control == IOBUFCTRL_UNDERFLOW ) { if( !zfx->status ) { zs = zfx->opaque = m_alloc_clear( sizeof *zs ); init_uncompress( zfx, zs ); zfx->status = 1; } #ifndef __riscos__ zs->next_out = buf; #else /* __riscos__ */ zs->next_out = (Bytef *) buf; #endif /* __riscos__ */ zs->avail_out = size; zfx->outbufsize = size; /* needed only for calculation */ rc = do_uncompress( zfx, zs, a, ret_len ); } else if( control == IOBUFCTRL_FLUSH ) { if( !zfx->status ) { PACKET pkt; PKT_compressed cd; if( !zfx->algo ) zfx->algo = DEFAULT_COMPRESS_ALGO; if( zfx->algo != 1 && zfx->algo != 2 ) BUG(); memset( &cd, 0, sizeof cd ); cd.len = 0; cd.algorithm = zfx->algo; init_packet( &pkt ); pkt.pkttype = PKT_COMPRESSED; pkt.pkt.compressed = &cd; if( build_packet( a, &pkt )) log_bug("build_packet(PKT_COMPRESSED) failed\n"); zs = zfx->opaque = m_alloc_clear( sizeof *zs ); init_compress( zfx, zs ); zfx->status = 2; } #ifndef __riscos__ zs->next_in = buf; #else /* __riscos__ */ zs->next_in = (Bytef *) buf; #endif /* __riscos__ */ zs->avail_in = size; rc = do_compress( zfx, zs, Z_NO_FLUSH, a ); } else if( control == IOBUFCTRL_FREE ) { if( zfx->status == 1 ) { inflateEnd(zs); m_free(zs); zfx->opaque = NULL; m_free(zfx->outbuf); zfx->outbuf = NULL; } else if( zfx->status == 2 ) { #ifndef __riscos__ zs->next_in = buf; #else /* __riscos__ */ zs->next_in = (Bytef *) buf; #endif /* __riscos__ */ zs->avail_in = 0; do_compress( zfx, zs, Z_FINISH, a ); deflateEnd(zs); m_free(zs); zfx->opaque = NULL; m_free(zfx->outbuf); zfx->outbuf = NULL; } if (zfx->release) zfx->release (zfx); } else if( control == IOBUFCTRL_DESC ) *(char**)buf = "compress_filter"; return rc; }
/* Initialize POOL. */ static void init_pool (size_t n) { size_t pgsize; memblock_t *mb; pool_size = n; if (disable_secmem) log_bug ("secure memory is disabled"); #ifdef HAVE_GETPAGESIZE pgsize = getpagesize (); #else pgsize = DEFAULT_PAGE_SIZE; #endif #if HAVE_MMAP pool_size = (pool_size + pgsize - 1) & ~(pgsize - 1); #ifdef MAP_ANONYMOUS pool = mmap (0, pool_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #else /* map /dev/zero instead */ { int fd; fd = open ("/dev/zero", O_RDWR); if (fd == -1) { log_error ("can't open /dev/zero: %s\n", strerror (errno)); pool = (void *) -1; } else { pool = mmap (0, pool_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); } } #endif if (pool == (void *) -1) log_info ("can't mmap pool of %u bytes: %s - using malloc\n", (unsigned) pool_size, strerror (errno)); else { pool_is_mmapped = 1; pool_okay = 1; } #endif if (!pool_okay) { pool = malloc (pool_size); if (!pool) log_fatal ("can't allocate memory pool of %u bytes\n", (unsigned) pool_size); else pool_okay = 1; } /* Initialize first memory block. */ mb = (memblock_t *) pool; mb->size = pool_size; mb->flags = 0; }
/**************** * Build a packet and write it to INP * Returns: 0 := okay * >0 := error * Note: Caller must free the packet */ int build_packet( IOBUF out, PACKET *pkt ) { int new_ctb=0, rc=0, ctb; int pkttype; if( DBG_PACKET ) log_debug("build_packet() type=%d\n", pkt->pkttype ); assert( pkt->pkt.generic ); switch( (pkttype = pkt->pkttype) ) { case PKT_OLD_COMMENT: pkttype = pkt->pkttype = PKT_COMMENT; break; case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: new_ctb = pkt->pkt.encrypted->new_ctb; break; case PKT_COMPRESSED:new_ctb = pkt->pkt.compressed->new_ctb; break; case PKT_USER_ID: if( pkt->pkt.user_id->photo ) pkttype = PKT_PHOTO_ID; break; default: break; } if( new_ctb || pkttype > 15 ) /* new format */ ctb = 0xc0 | (pkttype & 0x3f); else ctb = 0x80 | ((pkttype & 15)<<2); switch( pkttype ) { case PKT_PHOTO_ID: case PKT_USER_ID: rc = do_user_id( out, ctb, pkt->pkt.user_id ); break; case PKT_COMMENT: rc = do_comment( out, ctb, pkt->pkt.comment ); break; case PKT_PUBLIC_SUBKEY: case PKT_PUBLIC_KEY: rc = do_public_key( out, ctb, pkt->pkt.public_key ); break; case PKT_SECRET_SUBKEY: case PKT_SECRET_KEY: rc = do_secret_key( out, ctb, pkt->pkt.secret_key ); break; case PKT_SYMKEY_ENC: rc = do_symkey_enc( out, ctb, pkt->pkt.symkey_enc ); break; case PKT_PUBKEY_ENC: rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc ); break; case PKT_PLAINTEXT: rc = do_plaintext( out, ctb, pkt->pkt.plaintext ); break; case PKT_ENCRYPTED: rc = do_encrypted( out, ctb, pkt->pkt.encrypted ); break; case PKT_ENCRYPTED_MDC: rc = do_encrypted_mdc( out, ctb, pkt->pkt.encrypted ); break; case PKT_MDC: rc = do_mdc( out, pkt->pkt.mdc ); break; case PKT_COMPRESSED: rc = do_compressed( out, ctb, pkt->pkt.compressed ); break; case PKT_SIGNATURE: rc = do_signature( out, ctb, pkt->pkt.signature ); break; case PKT_ONEPASS_SIG: rc = do_onepass_sig( out, ctb, pkt->pkt.onepass_sig ); break; case PKT_RING_TRUST: break; /* ignore it */ default: log_bug("invalid packet type in build_packet()\n"); break; } return rc; }
int compress_filter_bz2( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { size_t size = *ret_len; compress_filter_context_t *zfx = opaque; bz_stream *bzs = zfx->opaque; int rc=0; if( control == IOBUFCTRL_UNDERFLOW ) { if( !zfx->status ) { bzs = zfx->opaque = xmalloc_clear( sizeof *bzs ); init_uncompress( zfx, bzs ); zfx->status = 1; } bzs->next_out = buf; bzs->avail_out = size; zfx->outbufsize = size; /* needed only for calculation */ rc = do_uncompress( zfx, bzs, a, ret_len ); } else if( control == IOBUFCTRL_FLUSH ) { if( !zfx->status ) { PACKET pkt; PKT_compressed cd; if( zfx->algo != COMPRESS_ALGO_BZIP2 ) BUG(); memset( &cd, 0, sizeof cd ); cd.len = 0; cd.algorithm = zfx->algo; init_packet( &pkt ); pkt.pkttype = PKT_COMPRESSED; pkt.pkt.compressed = &cd; if( build_packet( a, &pkt )) log_bug("build_packet(PKT_COMPRESSED) failed\n"); bzs = zfx->opaque = xmalloc_clear( sizeof *bzs ); init_compress( zfx, bzs ); zfx->status = 2; } bzs->next_in = buf; bzs->avail_in = size; rc = do_compress( zfx, bzs, BZ_RUN, a ); } else if( control == IOBUFCTRL_FREE ) { if( zfx->status == 1 ) { BZ2_bzDecompressEnd(bzs); xfree(bzs); zfx->opaque = NULL; xfree(zfx->outbuf); zfx->outbuf = NULL; } else if( zfx->status == 2 ) { bzs->next_in = buf; bzs->avail_in = 0; do_compress( zfx, bzs, BZ_FINISH, a ); BZ2_bzCompressEnd(bzs); xfree(bzs); zfx->opaque = NULL; xfree(zfx->outbuf); zfx->outbuf = NULL; } if (zfx->release) zfx->release (zfx); } else if( control == IOBUFCTRL_DESC ) *(char**)buf = "compress_filter"; return rc; }
static void read_pool( byte *buffer, size_t length, int level ) { int i; ulong *sp, *dp; if( length > POOLSIZE ) { log_bug("too many random bits requested\n"); } if( !pool_filled ) { if( read_seed_file() ) pool_filled = 1; } /* For level 2 quality (key generation) we alwas make * sure that the pool has been seeded enough initially */ if( level == 2 && !did_initial_extra_seeding ) { size_t needed; pool_balance = 0; needed = length - pool_balance; if( needed < POOLSIZE/2 ) needed = POOLSIZE/2; else if( needed > POOLSIZE ) BUG(); read_random_source( 3, needed, 2 ); pool_balance += needed; did_initial_extra_seeding=1; } /* for level 2 make sure that there is enough random in the pool */ if( level == 2 && pool_balance < length ) { size_t needed; if( pool_balance < 0 ) pool_balance = 0; needed = length - pool_balance; if( needed > POOLSIZE ) BUG(); read_random_source( 3, needed, 2 ); pool_balance += needed; } /* make sure the pool is filled */ while( !pool_filled ) random_poll(); /* do always a fast random poll */ fast_random_poll(); if( !level ) { /* no need for cryptographic strong random */ /* create a new pool */ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) *dp = *sp + ADD_VALUE; /* must mix both pools */ mix_pool(rndpool); rndstats.mixrnd++; mix_pool(keypool); rndstats.mixkey++; memcpy( buffer, keypool, length ); } else { /* mix the pool (if add_randomness() didn't it) */ if( !just_mixed ) { mix_pool(rndpool); rndstats.mixrnd++; } /* create a new pool */ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) *dp = *sp + ADD_VALUE; /* and mix both pools */ mix_pool(rndpool); rndstats.mixrnd++; mix_pool(keypool); rndstats.mixkey++; /* read the required data * we use a readpoiter to read from a different postion each * time */ while( length-- ) { *buffer++ = keypool[pool_readpos++]; if( pool_readpos >= POOLSIZE ) pool_readpos = 0; pool_balance--; } if( pool_balance < 0 ) pool_balance = 0; /* and clear the keypool */ memset( keypool, 0, POOLSIZE ); } }