static int watchccs_read(BIO *bio, char *out, int outl) { int ret = 0; BIO *next = BIO_next(bio); if (outl <= 0) return 0; if (next == NULL) return 0; BIO_clear_retry_flags(bio); ret = BIO_read(next, out, outl); if (ret <= 0 && BIO_should_read(next)) BIO_set_retry_read(bio); return ret; }
static long watchccs_ctrl(BIO *bio, int cmd, long num, void *ptr) { long ret; BIO *next = BIO_next(bio); if (next == NULL) return 0; switch (cmd) { case BIO_CTRL_DUP: ret = 0; break; default: ret = BIO_ctrl(next, cmd, num, ptr); break; } return ret; }
static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { for (;;) { bio = BIO_find_type(bio, BIO_TYPE_MD); if (bio == NULL) { PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); return NULL; } BIO_get_md_ctx(bio, pmd); if (*pmd == NULL) { PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST, ERR_R_INTERNAL_ERROR); return NULL; } if (EVP_MD_CTX_type(*pmd) == nid) return bio; bio = BIO_next(bio); } return NULL; }
static long transport_bio_buffered_ctrl(BIO* bio, int cmd, long arg1, void* arg2) { int status = -1; WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*) BIO_get_data(bio); switch (cmd) { case BIO_CTRL_FLUSH: if (!ringbuffer_used(&ptr->xmitBuffer)) status = 1; else status = (transport_bio_buffered_write(bio, NULL, 0) >= 0) ? 1 : -1; break; case BIO_CTRL_WPENDING: status = ringbuffer_used(&ptr->xmitBuffer); break; case BIO_CTRL_PENDING: status = 0; break; case BIO_C_READ_BLOCKED: status = (int) ptr->readBlocked; break; case BIO_C_WRITE_BLOCKED: status = (int) ptr->writeBlocked; break; default: status = BIO_ctrl(BIO_next(bio), cmd, arg1, arg2); break; } return status; }
static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, asn1_ps_func *cleanup, asn1_bio_state_t next) { int ret; if (ctx->ex_len <= 0) return 1; for (;;) { ret = BIO_write(BIO_next(b), ctx->ex_buf + ctx->ex_pos, ctx->ex_len); if (ret <= 0) break; ctx->ex_len -= ret; if (ctx->ex_len > 0) ctx->ex_pos += ret; else { if (cleanup) cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg); ctx->state = next; ctx->ex_pos = 0; break; } } return ret; }
static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) { BIO* ssl_rbio; BIO* ssl_wbio; BIO* next_bio; int status = -1; BIO_RDP_TLS* tls = (BIO_RDP_TLS*) BIO_get_data(bio); if (!tls) return 0; if (!tls->ssl && (cmd != BIO_C_SET_SSL)) return 0; next_bio = BIO_next(bio); ssl_rbio = tls->ssl ? SSL_get_rbio(tls->ssl) : NULL; ssl_wbio = tls->ssl ? SSL_get_wbio(tls->ssl) : NULL; switch (cmd) { case BIO_CTRL_RESET: SSL_shutdown(tls->ssl); if (SSL_in_connect_init(tls->ssl)) SSL_set_connect_state(tls->ssl); else if (SSL_in_accept_init(tls->ssl)) SSL_set_accept_state(tls->ssl); SSL_clear(tls->ssl); if (next_bio) status = BIO_ctrl(next_bio, cmd, num, ptr); else if (ssl_rbio) status = BIO_ctrl(ssl_rbio, cmd, num, ptr); else status = 1; break; case BIO_C_GET_FD: status = BIO_ctrl(ssl_rbio, cmd, num, ptr); break; case BIO_CTRL_INFO: status = 0; break; case BIO_CTRL_SET_CALLBACK: status = 0; break; case BIO_CTRL_GET_CALLBACK: *((ULONG_PTR*) ptr) = (ULONG_PTR) SSL_get_info_callback(tls->ssl); status = 1; break; case BIO_C_SSL_MODE: if (num) SSL_set_connect_state(tls->ssl); else SSL_set_accept_state(tls->ssl); status = 1; break; case BIO_CTRL_GET_CLOSE: status = BIO_get_shutdown(bio); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(bio, (int) num); status = 1; break; case BIO_CTRL_WPENDING: status = BIO_ctrl(ssl_wbio, cmd, num, ptr); break; case BIO_CTRL_PENDING: status = SSL_pending(tls->ssl); if (status == 0) status = BIO_pending(ssl_rbio); break; case BIO_CTRL_FLUSH: BIO_clear_retry_flags(bio); status = BIO_ctrl(ssl_wbio, cmd, num, ptr); BIO_copy_next_retry(bio); status = 1; break; case BIO_CTRL_PUSH: if (next_bio && (next_bio != ssl_rbio)) { #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_set_bio(tls->ssl, next_bio, next_bio); CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO); #else /* * We are going to pass ownership of next to the SSL object...but * we don't own a reference to pass yet - so up ref */ BIO_up_ref(next_bio); SSL_set_bio(tls->ssl, next_bio, next_bio); #endif } status = 1; break; case BIO_CTRL_POP: /* Only detach if we are the BIO explicitly being popped */ if (bio == ptr) { if (ssl_rbio != ssl_wbio) BIO_free_all(ssl_wbio); #if OPENSSL_VERSION_NUMBER < 0x10100000L if (next_bio) CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO); tls->ssl->wbio = tls->ssl->rbio = NULL; #else /* OpenSSL 1.1: This will also clear the reference we obtained during push */ SSL_set_bio(tls->ssl, NULL, NULL); #endif } status = 1; break; case BIO_C_GET_SSL: if (ptr) { *((SSL**) ptr) = tls->ssl; status = 1; } break; case BIO_C_SET_SSL: BIO_set_shutdown(bio, (int) num); if (ptr) { tls->ssl = (SSL*) ptr; ssl_rbio = SSL_get_rbio(tls->ssl); ssl_wbio = SSL_get_wbio(tls->ssl); } if (ssl_rbio) { if (next_bio) BIO_push(ssl_rbio, next_bio); BIO_set_next(bio, ssl_rbio); #if OPENSSL_VERSION_NUMBER < 0x10100000L CRYPTO_add(&(ssl_rbio->references), 1, CRYPTO_LOCK_BIO); #else BIO_up_ref(ssl_rbio); #endif } BIO_set_init(bio, 1); status = 1; break; case BIO_C_DO_STATE_MACHINE: BIO_clear_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL); BIO_set_retry_reason(bio, 0); status = SSL_do_handshake(tls->ssl); if (status <= 0) { switch (SSL_get_error(tls->ssl, status)) { case SSL_ERROR_WANT_READ: BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_WRITE: BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_CONNECT: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY); BIO_set_retry_reason(bio, BIO_get_retry_reason(next_bio)); break; default: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; } } break; default: status = BIO_ctrl(ssl_rbio, cmd, num, ptr); break; } return status; }
static long ok_ctrl(BIO *b, int cmd, long num, void *ptr) { BIO_OK_CTX *ctx; EVP_MD *md; const EVP_MD **ppmd; long ret = 1; int i; BIO *next; ctx = BIO_get_data(b); next = BIO_next(b); switch (cmd) { case BIO_CTRL_RESET: ctx->buf_len = 0; ctx->buf_off = 0; ctx->buf_len_save = 0; ctx->buf_off_save = 0; ctx->cont = 1; ctx->finished = 0; ctx->blockout = 0; ctx->sigio = 1; ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_EOF: /* More to read */ if (ctx->cont <= 0) ret = 1; else ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_PENDING: /* More to read in buffer */ case BIO_CTRL_WPENDING: /* More to read in buffer */ ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0; if (ret <= 0) ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_FLUSH: /* do a final write */ if (ctx->blockout == 0) if (!block_out(b)) return 0; while (ctx->blockout) { i = ok_write(b, NULL, 0); if (i < 0) { ret = i; break; } } ctx->finished = 1; ctx->buf_off = ctx->buf_len = 0; ctx->cont = (int)ret; /* Finally flush the underlying BIO */ ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); ret = BIO_ctrl(next, cmd, num, ptr); BIO_copy_next_retry(b); break; case BIO_CTRL_INFO: ret = (long)ctx->cont; break; case BIO_C_SET_MD: md = ptr; if (!EVP_DigestInit_ex(ctx->md, md, NULL)) return 0; BIO_set_init(b, 1); break; case BIO_C_GET_MD: if (BIO_get_init(b)) { ppmd = ptr; *ppmd = EVP_MD_CTX_md(ctx->md); } else ret = 0; break; default: ret = BIO_ctrl(next, cmd, num, ptr); break; } return ret; }
static int ok_read(BIO *b, char *out, int outl) { int ret = 0, i, n; BIO_OK_CTX *ctx; BIO *next; if (out == NULL) return 0; ctx = BIO_get_data(b); next = BIO_next(b); if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0)) return 0; while (outl > 0) { /* copy clean bytes to output buffer */ if (ctx->blockout) { i = ctx->buf_len - ctx->buf_off; if (i > outl) i = outl; memcpy(out, &(ctx->buf[ctx->buf_off]), i); ret += i; out += i; outl -= i; ctx->buf_off += i; /* all clean bytes are out */ if (ctx->buf_len == ctx->buf_off) { ctx->buf_off = 0; /* * copy start of the next block into proper place */ if (ctx->buf_len_save - ctx->buf_off_save > 0) { ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save; memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]), ctx->buf_len); } else { ctx->buf_len = 0; } ctx->blockout = 0; } } /* output buffer full -- cancel */ if (outl == 0) break; /* no clean bytes in buffer -- fill it */ n = IOBS - ctx->buf_len; i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n); if (i <= 0) break; /* nothing new */ ctx->buf_len += i; /* no signature yet -- check if we got one */ if (ctx->sigio == 1) { if (!sig_in(b)) { BIO_clear_retry_flags(b); return 0; } } /* signature ok -- check if we got block */ if (ctx->sigio == 0) { if (!block_in(b)) { BIO_clear_retry_flags(b); return 0; } } /* invalid block -- cancel */ if (ctx->cont <= 0) break; } BIO_clear_retry_flags(b); BIO_copy_next_retry(b); return ret; }
static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr) { BIO_ZLIB_CTX *ctx; int ret, *ip; int ibs, obs; BIO *next = BIO_next(b); if (next == NULL) return 0; ctx = BIO_get_data(b); switch (cmd) { case BIO_CTRL_RESET: ctx->ocount = 0; ctx->odone = 0; ret = 1; break; case BIO_CTRL_FLUSH: ret = bio_zlib_flush(b); if (ret > 0) ret = BIO_flush(next); break; case BIO_C_SET_BUFF_SIZE: ibs = -1; obs = -1; if (ptr != NULL) { ip = ptr; if (*ip == 0) ibs = (int)num; else obs = (int)num; } else { ibs = (int)num; obs = ibs; } if (ibs != -1) { OPENSSL_free(ctx->ibuf); ctx->ibuf = NULL; ctx->ibufsize = ibs; } if (obs != -1) { OPENSSL_free(ctx->obuf); ctx->obuf = NULL; ctx->obufsize = obs; } ret = 1; break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); ret = BIO_ctrl(next, cmd, num, ptr); BIO_copy_next_retry(b); break; default: ret = BIO_ctrl(next, cmd, num, ptr); break; } return ret; }
int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { int ret=0; int i,j; BIO *btmp; BUF_MEM *buf_mem=NULL; BUF_MEM *buf=NULL; PKCS7_SIGNER_INFO *si; EVP_MD_CTX *mdc,ctx_tmp; STACK_OF(X509_ATTRIBUTE) *sk; STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL; ASN1_OCTET_STRING *os=NULL; EVP_MD_CTX_init(&ctx_tmp); i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signedAndEnveloped: /* XXXXXXXXXXXXXXXX */ si_sk=p7->d.signed_and_enveloped->signer_info; os=M_ASN1_OCTET_STRING_new(); p7->d.signed_and_enveloped->enc_data->enc_data=os; break; case NID_pkcs7_enveloped: /* XXXXXXXXXXXXXXXX */ os=M_ASN1_OCTET_STRING_new(); p7->d.enveloped->enc_data->enc_data=os; break; case NID_pkcs7_signed: si_sk=p7->d.sign->signer_info; os=p7->d.sign->contents->d.data; /* If detached data then the content is excluded */ if(p7->detached) { M_ASN1_OCTET_STRING_free(os); p7->d.sign->contents->d.data = NULL; } break; } if (si_sk != NULL) { if ((buf=BUF_MEM_new()) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_BIO_LIB); goto err; } for (i=0; i<sk_PKCS7_SIGNER_INFO_num(si_sk); i++) { si=sk_PKCS7_SIGNER_INFO_value(si_sk,i); if (si->pkey == NULL) continue; j=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; for (;;) { if ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATASIGN,PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } BIO_get_md_ctx(btmp,&mdc); if (mdc == NULL) { PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_INTERNAL_ERROR); goto err; } if (EVP_MD_CTX_type(mdc) == j) break; else btmp=BIO_next(btmp); } /* We now have the EVP_MD_CTX, lets do the * signing. */ EVP_MD_CTX_copy_ex(&ctx_tmp,mdc); if (!BUF_MEM_grow_clean(buf,EVP_PKEY_size(si->pkey))) { PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_BIO_LIB); goto err; } sk=si->auth_attr; /* If there are attributes, we add the digest * attribute and only sign the attributes */ if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { unsigned char md_data[EVP_MAX_MD_SIZE], *abuf=NULL; unsigned int md_len, alen; ASN1_OCTET_STRING *digest; ASN1_UTCTIME *sign_time; const EVP_MD *md_tmp; /* Add signing time if not already present */ if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) { sign_time=X509_gmtime_adj(NULL,0); PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, V_ASN1_UTCTIME,sign_time); } /* Add digest */ md_tmp=EVP_MD_CTX_md(&ctx_tmp); EVP_DigestFinal_ex(&ctx_tmp,md_data,&md_len); digest=M_ASN1_OCTET_STRING_new(); M_ASN1_OCTET_STRING_set(digest,md_data,md_len); PKCS7_add_signed_attribute(si, NID_pkcs9_messageDigest, V_ASN1_OCTET_STRING,digest); /* Now sign the attributes */ EVP_SignInit_ex(&ctx_tmp,md_tmp,NULL); alen = ASN1_item_i2d((ASN1_VALUE *)sk,&abuf, ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); if(!abuf) goto err; EVP_SignUpdate(&ctx_tmp,abuf,alen); OPENSSL_free(abuf); } #ifndef OPENSSL_NO_DSA if (si->pkey->type == EVP_PKEY_DSA) ctx_tmp.digest=EVP_dss1(); #endif if (!EVP_SignFinal(&ctx_tmp,(unsigned char *)buf->data, (unsigned int *)&buf->length,si->pkey)) { PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_EVP_LIB); goto err; } if (!ASN1_STRING_set(si->enc_digest, (unsigned char *)buf->data,buf->length)) { PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_ASN1_LIB); goto err; } } } if (!PKCS7_is_detached(p7)) { btmp=BIO_find_type(bio,BIO_TYPE_MEM); if (btmp == NULL) { PKCS7err(PKCS7_F_PKCS7_DATASIGN,PKCS7_R_UNABLE_TO_FIND_MEM_BIO); goto err; } BIO_get_mem_ptr(btmp,&buf_mem); /* Mark the BIO read only then we can use its copy of the data * instead of making an extra copy. */ BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); BIO_set_mem_eof_return(btmp, 0); os->data = (unsigned char *)buf_mem->data; os->length = buf_mem->length; #if 0 M_ASN1_OCTET_STRING_set(os, (unsigned char *)buf_mem->data,buf_mem->length); #endif } ret=1; err: EVP_MD_CTX_cleanup(&ctx_tmp); if (buf != NULL) BUF_MEM_free(buf); return(ret); }
static int tap_gets(BIO *b, char *buf, int size) { return BIO_gets(BIO_next(b), buf, size); }
static long tap_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) { return BIO_callback_ctrl(BIO_next(b), cmd, fp); }
static int enc_read(BIO *b, char *out, int outl) { int ret = 0, i; BIO_ENC_CTX *ctx; BIO *next; if (out == NULL) return (0); ctx = BIO_get_data(b); next = BIO_next(b); if ((ctx == NULL) || (next == NULL)) return 0; /* First check if there are bytes decoded/encoded */ if (ctx->buf_len > 0) { i = ctx->buf_len - ctx->buf_off; if (i > outl) i = outl; memcpy(out, &(ctx->buf[ctx->buf_off]), i); ret = i; out += i; outl -= i; ctx->buf_off += i; if (ctx->buf_len == ctx->buf_off) { ctx->buf_len = 0; ctx->buf_off = 0; } } /* * At this point, we have room of outl bytes and an empty buffer, so we * should read in some more. */ while (outl > 0) { if (ctx->cont <= 0) break; /* * read in at IV offset, read the EVP_Cipher documentation about why */ i = BIO_read(next, &(ctx->buf[BUF_OFFSET]), ENC_BLOCK_SIZE); if (i <= 0) { /* Should be continue next time we are called? */ if (!BIO_should_retry(next)) { ctx->cont = i; i = EVP_CipherFinal_ex(ctx->cipher, (unsigned char *)ctx->buf, &(ctx->buf_len)); ctx->ok = i; ctx->buf_off = 0; } else { ret = (ret == 0) ? i : ret; break; } } else { if (!EVP_CipherUpdate(ctx->cipher, (unsigned char *)ctx->buf, &ctx->buf_len, (unsigned char *)&(ctx->buf[BUF_OFFSET]), i)) { BIO_clear_retry_flags(b); ctx->ok = 0; return 0; } ctx->cont = 1; /* * Note: it is possible for EVP_CipherUpdate to decrypt zero * bytes because this is or looks like the final block: if this * happens we should retry and either read more data or decrypt * the final block */ if (ctx->buf_len == 0) continue; } if (ctx->buf_len <= outl) i = ctx->buf_len; else i = outl; if (i <= 0) break; memcpy(out, ctx->buf, i); ret += i; ctx->buf_off = i; outl -= i; out += i; } BIO_clear_retry_flags(b); BIO_copy_next_retry(b); return ((ret == 0) ? ctx->cont : ret); }
int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509) { ASN1_OCTET_STRING *os; EVP_MD_CTX mdc_tmp,*mdc; unsigned char *pp,*p; int ret=0,i; int md_type; STACK_OF(X509_ATTRIBUTE) *sk; BIO *btmp; EVP_PKEY *pkey; if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); goto err; } md_type=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; for (;;) { if ((btmp == NULL) || ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } BIO_get_md_ctx(btmp,&mdc); if (mdc == NULL) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_INTERNAL_ERROR); goto err; } if (EVP_MD_CTX_type(mdc) == md_type) break; btmp=BIO_next(btmp); } /* mdc is the digest ctx that we want, unless there are attributes, * in which case the digest is the signed attributes */ memcpy(&mdc_tmp,mdc,sizeof(mdc_tmp)); sk=si->auth_attr; if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { unsigned char md_dat[EVP_MAX_MD_SIZE]; unsigned int md_len; ASN1_OCTET_STRING *message_digest; EVP_DigestFinal(&mdc_tmp,md_dat,&md_len); message_digest=PKCS7_digest_from_attributes(sk); if (!message_digest) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } if ((message_digest->length != (int)md_len) || (memcmp(message_digest->data,md_dat,md_len))) { #if 0 { int ii; for (ii=0; ii<message_digest->length; ii++) printf("%02X",message_digest->data[ii]); printf(" sent\n"); for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n"); } #endif PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_DIGEST_FAILURE); ret= -1; goto err; } EVP_VerifyInit(&mdc_tmp,EVP_get_digestbynid(md_type)); /* Note: when forming the encoding of the attributes we * shouldn't reorder them or this will break the signature. * This is done by using the IS_SEQUENCE flag. */ i=i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,NULL,i2d_X509_ATTRIBUTE, V_ASN1_SET,V_ASN1_UNIVERSAL, IS_SEQUENCE); pp=OPENSSL_malloc(i); p=pp; i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,&p,i2d_X509_ATTRIBUTE, V_ASN1_SET,V_ASN1_UNIVERSAL, IS_SEQUENCE); EVP_VerifyUpdate(&mdc_tmp,pp,i); OPENSSL_free(pp); } os=si->enc_digest; pkey = X509_get_pubkey(x509); if (!pkey) { ret = -1; goto err; } #ifndef NO_DSA if(pkey->type == EVP_PKEY_DSA) mdc_tmp.digest=EVP_dss1(); #endif i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey); EVP_PKEY_free(pkey); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); ret= -1; goto err; } else ret=1; err: return(ret); }
static int watchccs_write(BIO *bio, const char *in, int inl) { int ret = 0; BIO *next = BIO_next(bio); PACKET pkt, msg, msgbody, sessionid; unsigned int rectype, recvers, msgtype, expectedrecvers; if (inl <= 0) return 0; if (next == NULL) return 0; BIO_clear_retry_flags(bio); if (!PACKET_buf_init(&pkt, (const unsigned char *)in, inl)) return 0; /* We assume that we always write complete records each time */ while (PACKET_remaining(&pkt)) { if (!PACKET_get_1(&pkt, &rectype) || !PACKET_get_net_2(&pkt, &recvers) || !PACKET_get_length_prefixed_2(&pkt, &msg)) return 0; expectedrecvers = TLS1_2_VERSION; if (rectype == SSL3_RT_HANDSHAKE) { if (!PACKET_get_1(&msg, &msgtype) || !PACKET_get_length_prefixed_3(&msg, &msgbody)) return 0; if (msgtype == SSL3_MT_CLIENT_HELLO) { chseen++; /* * Skip legacy_version (2 bytes) and Random (32 bytes) to read * session_id. */ if (!PACKET_forward(&msgbody, 34) || !PACKET_get_length_prefixed_1(&msgbody, &sessionid)) return 0; if (chseen == 1) { expectedrecvers = TLS1_VERSION; /* Save the session id for later */ chsessidlen = PACKET_remaining(&sessionid); if (!PACKET_copy_bytes(&sessionid, chsessid, chsessidlen)) return 0; } else { /* * Check the session id for the second ClientHello is the * same as the first one. */ if (PACKET_remaining(&sessionid) != chsessidlen || (chsessidlen > 0 && memcmp(chsessid, PACKET_data(&sessionid), chsessidlen) != 0)) badsessid = 1; } } else if (msgtype == SSL3_MT_SERVER_HELLO) { shseen++; /* * Skip legacy_version (2 bytes) and Random (32 bytes) to read * session_id. */ if (!PACKET_forward(&msgbody, 34) || !PACKET_get_length_prefixed_1(&msgbody, &sessionid)) return 0; /* * Check the session id is the same as the one in the * ClientHello */ if (PACKET_remaining(&sessionid) != chsessidlen || (chsessidlen > 0 && memcmp(chsessid, PACKET_data(&sessionid), chsessidlen) != 0)) badsessid = 1; } } else if (rectype == SSL3_RT_CHANGE_CIPHER_SPEC) { if (bio == s_to_c_fbio) { /* * Server writing. We shouldn't have written any app data * yet, and we should have seen both the ClientHello and the * ServerHello */ if (!sappdataseen && chseen == 1 && shseen == 1 && !sccsseen) sccsseen = 1; else badccs = 1; } else if (!cappdataseen) { /* * Client writing. We shouldn't have written any app data * yet, and we should have seen the ClientHello */ if (shseen == 1 && !ccsaftersh) ccsaftersh = 1; else if (shseen == 0 && !ccsbeforesh) ccsbeforesh = 1; else badccs = 1; } else { badccs = 1; } } else if(rectype == SSL3_RT_APPLICATION_DATA) { if (bio == s_to_c_fbio) sappdataseen = 1; else cappdataseen = 1; } if (recvers != expectedrecvers) badvers = 1; } ret = BIO_write(next, in, inl); if (ret <= 0 && BIO_should_write(next)) BIO_set_retry_write(bio); return ret; }
static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) { int i, ret; int status; int nchunks; int committedBytes; DataChunk chunks[2]; WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*) BIO_get_data(bio); BIO* next_bio = NULL; ret = num; ptr->writeBlocked = FALSE; BIO_clear_flags(bio, BIO_FLAGS_WRITE); /* we directly append extra bytes in the xmit buffer, this could be prevented * but for now it makes the code more simple. */ if (buf && num && !ringbuffer_write(&ptr->xmitBuffer, (const BYTE*) buf, num)) { WLog_ERR(TAG, "an error occurred when writing (num: %d)", num); return -1; } committedBytes = 0; nchunks = ringbuffer_peek(&ptr->xmitBuffer, chunks, ringbuffer_used(&ptr->xmitBuffer)); next_bio = BIO_next(bio); for (i = 0; i < nchunks; i++) { while (chunks[i].size) { status = BIO_write(next_bio, chunks[i].data, chunks[i].size); if (status <= 0) { if (!BIO_should_retry(next_bio)) { BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); ret = -1; /* fatal error */ goto out; } if (BIO_should_write(next_bio)) { BIO_set_flags(bio, BIO_FLAGS_WRITE); ptr->writeBlocked = TRUE; goto out; /* EWOULDBLOCK */ } } committedBytes += status; chunks[i].size -= status; chunks[i].data += status; } } out: ringbuffer_commit_read_bytes(&ptr->xmitBuffer, committedBytes); return ret; }
static int asn1_bio_write(BIO *b, const char *in, int inl) { BIO_ASN1_BUF_CTX *ctx; int wrmax, wrlen, ret; unsigned char *p; BIO *next; ctx = BIO_get_data(b); next = BIO_next(b); if (in == NULL || inl < 0 || ctx == NULL || next == NULL) return 0; wrlen = 0; ret = -1; for (;;) { switch (ctx->state) { /* Setup prefix data, call it */ case ASN1_STATE_START: if (!asn1_bio_setup_ex(b, ctx, ctx->prefix, ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER)) return 0; break; /* Copy any pre data first */ case ASN1_STATE_PRE_COPY: ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free, ASN1_STATE_HEADER); if (ret <= 0) goto done; break; case ASN1_STATE_HEADER: ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl; if (!ossl_assert(ctx->buflen <= ctx->bufsize)) return 0; p = ctx->buf; ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class); ctx->copylen = inl; ctx->state = ASN1_STATE_HEADER_COPY; break; case ASN1_STATE_HEADER_COPY: ret = BIO_write(next, ctx->buf + ctx->bufpos, ctx->buflen); if (ret <= 0) goto done; ctx->buflen -= ret; if (ctx->buflen) ctx->bufpos += ret; else { ctx->bufpos = 0; ctx->state = ASN1_STATE_DATA_COPY; } break; case ASN1_STATE_DATA_COPY: if (inl > ctx->copylen) wrmax = ctx->copylen; else wrmax = inl; ret = BIO_write(next, in, wrmax); if (ret <= 0) goto done; wrlen += ret; ctx->copylen -= ret; in += ret; inl -= ret; if (ctx->copylen == 0) ctx->state = ASN1_STATE_HEADER; if (inl == 0) goto done; break; case ASN1_STATE_POST_COPY: case ASN1_STATE_DONE: BIO_clear_retry_flags(b); return 0; } } done: BIO_clear_retry_flags(b); BIO_copy_next_retry(b); return (wrlen > 0) ? wrlen : ret; }
static int enc_read(BIO *b, char *out, int outl) { int ret = 0, i, blocksize; BIO_ENC_CTX *ctx; BIO *next; if (out == NULL) return (0); ctx = BIO_get_data(b); next = BIO_next(b); if ((ctx == NULL) || (next == NULL)) return 0; /* First check if there are bytes decoded/encoded */ if (ctx->buf_len > 0) { i = ctx->buf_len - ctx->buf_off; if (i > outl) i = outl; memcpy(out, &(ctx->buf[ctx->buf_off]), i); ret = i; out += i; outl -= i; ctx->buf_off += i; if (ctx->buf_len == ctx->buf_off) { ctx->buf_len = 0; ctx->buf_off = 0; } } blocksize = EVP_CIPHER_CTX_block_size(ctx->cipher); if (blocksize == 1) blocksize = 0; /* * At this point, we have room of outl bytes and an empty buffer, so we * should read in some more. */ while (outl > 0) { if (ctx->cont <= 0) break; if (ctx->read_start == ctx->read_end) { /* time to read more data */ ctx->read_end = ctx->read_start = &(ctx->buf[BUF_OFFSET]); ctx->read_end += BIO_read(next, ctx->read_start, ENC_BLOCK_SIZE); } i = ctx->read_end - ctx->read_start; if (i <= 0) { /* Should be continue next time we are called? */ if (!BIO_should_retry(next)) { ctx->cont = i; i = EVP_CipherFinal_ex(ctx->cipher, ctx->buf, &(ctx->buf_len)); ctx->ok = i; ctx->buf_off = 0; } else { ret = (ret == 0) ? i : ret; break; } } else { if (outl > ENC_MIN_CHUNK) { /* * Depending on flags block cipher decrypt can write * one extra block and then back off, i.e. output buffer * has to accommodate extra block... */ int j = outl - blocksize, buf_len; if (!EVP_CipherUpdate(ctx->cipher, (unsigned char *)out, &buf_len, ctx->read_start, i > j ? j : i)) { BIO_clear_retry_flags(b); return 0; } ret += buf_len; out += buf_len; outl -= buf_len; if ((i -= j) <= 0) { ctx->read_start = ctx->read_end; continue; } ctx->read_start += j; } if (i > ENC_MIN_CHUNK) i = ENC_MIN_CHUNK; if (!EVP_CipherUpdate(ctx->cipher, ctx->buf, &ctx->buf_len, ctx->read_start, i)) { BIO_clear_retry_flags(b); ctx->ok = 0; return 0; } ctx->read_start += i; ctx->cont = 1; /* * Note: it is possible for EVP_CipherUpdate to decrypt zero * bytes because this is or looks like the final block: if this * happens we should retry and either read more data or decrypt * the final block */ if (ctx->buf_len == 0) continue; } if (ctx->buf_len <= outl) i = ctx->buf_len; else i = outl; if (i <= 0) break; memcpy(out, ctx->buf, i); ret += i; ctx->buf_off = i; outl -= i; out += i; } BIO_clear_retry_flags(b); BIO_copy_next_retry(b); return ((ret == 0) ? ctx->cont : ret); }
static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2) { BIO_ASN1_BUF_CTX *ctx; BIO_ASN1_EX_FUNCS *ex_func; long ret = 1; BIO *next; ctx = BIO_get_data(b); if (ctx == NULL) return 0; next = BIO_next(b); switch (cmd) { case BIO_C_SET_PREFIX: ex_func = arg2; ctx->prefix = ex_func->ex_func; ctx->prefix_free = ex_func->ex_free_func; break; case BIO_C_GET_PREFIX: ex_func = arg2; ex_func->ex_func = ctx->prefix; ex_func->ex_free_func = ctx->prefix_free; break; case BIO_C_SET_SUFFIX: ex_func = arg2; ctx->suffix = ex_func->ex_func; ctx->suffix_free = ex_func->ex_free_func; break; case BIO_C_GET_SUFFIX: ex_func = arg2; ex_func->ex_func = ctx->suffix; ex_func->ex_free_func = ctx->suffix_free; break; case BIO_C_SET_EX_ARG: ctx->ex_arg = arg2; break; case BIO_C_GET_EX_ARG: *(void **)arg2 = ctx->ex_arg; break; case BIO_CTRL_FLUSH: if (next == NULL) return 0; /* Call post function if possible */ if (ctx->state == ASN1_STATE_HEADER) { if (!asn1_bio_setup_ex(b, ctx, ctx->suffix, ASN1_STATE_POST_COPY, ASN1_STATE_DONE)) return 0; } if (ctx->state == ASN1_STATE_POST_COPY) { ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free, ASN1_STATE_DONE); if (ret <= 0) return ret; } if (ctx->state == ASN1_STATE_DONE) return BIO_ctrl(next, cmd, arg1, arg2); else { BIO_clear_retry_flags(b); return 0; } default: if (next == NULL) return 0; return BIO_ctrl(next, cmd, arg1, arg2); } return ret; }
static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) { BIO *dbio; BIO_ENC_CTX *ctx, *dctx; long ret = 1; int i; EVP_CIPHER_CTX **c_ctx; BIO *next; ctx = BIO_get_data(b); next = BIO_next(b); if (ctx == NULL) return 0; switch (cmd) { case BIO_CTRL_RESET: ctx->ok = 1; ctx->finished = 0; if (!EVP_CipherInit_ex(ctx->cipher, NULL, NULL, NULL, NULL, EVP_CIPHER_CTX_encrypting(ctx->cipher))) return 0; ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_EOF: /* More to read */ if (ctx->cont <= 0) ret = 1; else ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_WPENDING: ret = ctx->buf_len - ctx->buf_off; if (ret <= 0) ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_PENDING: /* More to read in buffer */ ret = ctx->buf_len - ctx->buf_off; if (ret <= 0) ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_FLUSH: /* do a final write */ again: while (ctx->buf_len != ctx->buf_off) { i = enc_write(b, NULL, 0); if (i < 0) return i; } if (!ctx->finished) { ctx->finished = 1; ctx->buf_off = 0; ret = EVP_CipherFinal_ex(ctx->cipher, (unsigned char *)ctx->buf, &(ctx->buf_len)); ctx->ok = (int)ret; if (ret <= 0) break; /* push out the bytes */ goto again; } /* Finally flush the underlying BIO */ ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_C_GET_CIPHER_STATUS: ret = (long)ctx->ok; break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); ret = BIO_ctrl(next, cmd, num, ptr); BIO_copy_next_retry(b); break; case BIO_C_GET_CIPHER_CTX: c_ctx = (EVP_CIPHER_CTX **)ptr; *c_ctx = ctx->cipher; BIO_set_init(b, 1); break; case BIO_CTRL_DUP: dbio = (BIO *)ptr; dctx = BIO_get_data(dbio); dctx->cipher = EVP_CIPHER_CTX_new(); if (dctx->cipher == NULL) return 0; ret = EVP_CIPHER_CTX_copy(dctx->cipher, ctx->cipher); if (ret) BIO_set_init(dbio, 1); break; default: ret = BIO_ctrl(next, cmd, num, ptr); break; } return (ret); }
static int bio_zlib_write(BIO *b, const char *in, int inl) { BIO_ZLIB_CTX *ctx; int ret; z_stream *zout; BIO *next = BIO_next(b); if (!in || !inl) return 0; ctx = BIO_get_data(b); if (ctx->odone) return 0; zout = &ctx->zout; BIO_clear_retry_flags(b); if (!ctx->obuf) { ctx->obuf = OPENSSL_malloc(ctx->obufsize); /* Need error here */ if (ctx->obuf == NULL) { COMPerr(COMP_F_BIO_ZLIB_WRITE, ERR_R_MALLOC_FAILURE); return 0; } ctx->optr = ctx->obuf; ctx->ocount = 0; deflateInit(zout, ctx->comp_level); zout->next_out = ctx->obuf; zout->avail_out = ctx->obufsize; } /* Obtain input data directly from supplied buffer */ zout->next_in = (void *)in; zout->avail_in = inl; for (;;) { /* If data in output buffer write it first */ while (ctx->ocount) { ret = BIO_write(next, ctx->optr, ctx->ocount); if (ret <= 0) { /* Total data written */ int tot = inl - zout->avail_in; BIO_copy_next_retry(b); if (ret < 0) return (tot > 0) ? tot : ret; return tot; } ctx->optr += ret; ctx->ocount -= ret; } /* Have we consumed all supplied data? */ if (!zout->avail_in) return inl; /* Compress some more */ /* Reset buffer */ ctx->optr = ctx->obuf; zout->next_out = ctx->obuf; zout->avail_out = ctx->obufsize; /* Compress some more */ ret = deflate(zout, 0); if (ret != Z_OK) { COMPerr(COMP_F_BIO_ZLIB_WRITE, COMP_R_ZLIB_DEFLATE_ERROR); ERR_add_error_data(2, "zlib error:", zError(ret)); return 0; } ctx->ocount = ctx->obufsize - zout->avail_out; } }
static long ssl_ctrl(BIO *b, int cmd, long num, void *ptr) { SSL **sslp, *ssl; BIO_SSL *bs, *dbs; BIO *dbio, *bio; long ret = 1; BIO *next; bs = BIO_get_data(b); next = BIO_next(b); ssl = bs->ssl; if ((ssl == NULL) && (cmd != BIO_C_SET_SSL)) return 0; switch (cmd) { case BIO_CTRL_RESET: SSL_shutdown(ssl); if (ssl->handshake_func == ssl->method->ssl_connect) SSL_set_connect_state(ssl); else if (ssl->handshake_func == ssl->method->ssl_accept) SSL_set_accept_state(ssl); if (!SSL_clear(ssl)) { ret = 0; break; } if (next != NULL) ret = BIO_ctrl(next, cmd, num, ptr); else if (ssl->rbio != NULL) ret = BIO_ctrl(ssl->rbio, cmd, num, ptr); else ret = 1; break; case BIO_CTRL_INFO: ret = 0; break; case BIO_C_SSL_MODE: if (num) /* client mode */ SSL_set_connect_state(ssl); else SSL_set_accept_state(ssl); break; case BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT: ret = bs->renegotiate_timeout; if (num < 60) num = 5; bs->renegotiate_timeout = (unsigned long)num; bs->last_time = (unsigned long)time(NULL); break; case BIO_C_SET_SSL_RENEGOTIATE_BYTES: ret = bs->renegotiate_count; if ((long)num >= 512) bs->renegotiate_count = (unsigned long)num; break; case BIO_C_GET_SSL_NUM_RENEGOTIATES: ret = bs->num_renegotiates; break; case BIO_C_SET_SSL: if (ssl != NULL) { ssl_free(b); if (!ssl_new(b)) return 0; } BIO_set_shutdown(b, num); ssl = (SSL *)ptr; bs->ssl = ssl; bio = SSL_get_rbio(ssl); if (bio != NULL) { if (next != NULL) BIO_push(bio, next); BIO_set_next(b, bio); BIO_up_ref(bio); } BIO_set_init(b, 1); break; case BIO_C_GET_SSL: if (ptr != NULL) { sslp = (SSL **)ptr; *sslp = ssl; } else ret = 0; break; case BIO_CTRL_GET_CLOSE: ret = BIO_get_shutdown(b); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(b, (int)num); break; case BIO_CTRL_WPENDING: ret = BIO_ctrl(ssl->wbio, cmd, num, ptr); break; case BIO_CTRL_PENDING: ret = SSL_pending(ssl); if (ret == 0) ret = BIO_pending(ssl->rbio); break; case BIO_CTRL_FLUSH: BIO_clear_retry_flags(b); ret = BIO_ctrl(ssl->wbio, cmd, num, ptr); BIO_copy_next_retry(b); break; case BIO_CTRL_PUSH: if ((next != NULL) && (next != ssl->rbio)) { /* * We are going to pass ownership of next to the SSL object...but * we don't own a reference to pass yet - so up ref */ BIO_up_ref(next); SSL_set_bio(ssl, next, next); } break; case BIO_CTRL_POP: /* Only detach if we are the BIO explicitly being popped */ if (b == ptr) { /* This will clear the reference we obtained during push */ SSL_set_bio(ssl, NULL, NULL); } break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); BIO_set_retry_reason(b, 0); ret = (int)SSL_do_handshake(ssl); switch (SSL_get_error(ssl, (int)ret)) { case SSL_ERROR_WANT_READ: BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_WRITE: BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_CONNECT: BIO_set_flags(b, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY); BIO_set_retry_reason(b, BIO_get_retry_reason(next)); break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_set_retry_special(b); BIO_set_retry_reason(b, BIO_RR_SSL_X509_LOOKUP); break; default: break; } break; case BIO_CTRL_DUP: dbio = (BIO *)ptr; dbs = BIO_get_data(dbio); SSL_free(dbs->ssl); dbs->ssl = SSL_dup(ssl); dbs->num_renegotiates = bs->num_renegotiates; dbs->renegotiate_count = bs->renegotiate_count; dbs->byte_count = bs->byte_count; dbs->renegotiate_timeout = bs->renegotiate_timeout; dbs->last_time = bs->last_time; ret = (dbs->ssl != NULL); break; case BIO_C_GET_FD: ret = BIO_ctrl(ssl->rbio, cmd, num, ptr); break; case BIO_CTRL_SET_CALLBACK: ret = 0; /* use callback ctrl */ break; case BIO_CTRL_GET_CALLBACK: { void (**fptr) (const SSL *xssl, int type, int val); fptr = (void (**)(const SSL *xssl, int type, int val))ptr; *fptr = SSL_get_info_callback(ssl); } break; default: ret = BIO_ctrl(ssl->rbio, cmd, num, ptr); break; } return ret; }
static long md_ctrl(BIO *b, int cmd, long num, void *ptr) { EVP_MD_CTX *ctx, *dctx, **pctx; const EVP_MD **ppmd; EVP_MD *md; long ret = 1; BIO *dbio, *next; ctx = BIO_get_data(b); next = BIO_next(b); switch (cmd) { case BIO_CTRL_RESET: if (BIO_get_init(b)) ret = EVP_DigestInit_ex(ctx, ctx->digest, NULL); else ret = 0; if (ret > 0) ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_C_GET_MD: if (BIO_get_init(b)) { ppmd = ptr; *ppmd = ctx->digest; } else ret = 0; break; case BIO_C_GET_MD_CTX: pctx = ptr; *pctx = ctx; BIO_set_init(b, 1); break; case BIO_C_SET_MD_CTX: if (BIO_get_init(b)) BIO_set_data(b, ptr); else ret = 0; break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); ret = BIO_ctrl(next, cmd, num, ptr); BIO_copy_next_retry(b); break; case BIO_C_SET_MD: md = ptr; ret = EVP_DigestInit_ex(ctx, md, NULL); if (ret > 0) BIO_set_init(b, 1); break; case BIO_CTRL_DUP: dbio = ptr; dctx = BIO_get_data(dbio); if (!EVP_MD_CTX_copy_ex(dctx, ctx)) return 0; BIO_set_init(b, 1); break; default: ret = BIO_ctrl(next, cmd, num, ptr); break; } return ret; }
static int b64_read(BIO *b, char *out, int outl) { int ret = 0, i, ii, j, k, x, n, num, ret_code = 0; BIO_B64_CTX *ctx; unsigned char *p, *q; BIO *next; if (out == NULL) return 0; ctx = (BIO_B64_CTX *)BIO_get_data(b); next = BIO_next(b); if ((ctx == NULL) || (next == NULL)) return 0; BIO_clear_retry_flags(b); if (ctx->encode != B64_DECODE) { ctx->encode = B64_DECODE; ctx->buf_len = 0; ctx->buf_off = 0; ctx->tmp_len = 0; EVP_DecodeInit(ctx->base64); } /* First check if there are bytes decoded/encoded */ if (ctx->buf_len > 0) { OPENSSL_assert(ctx->buf_len >= ctx->buf_off); i = ctx->buf_len - ctx->buf_off; if (i > outl) i = outl; OPENSSL_assert(ctx->buf_off + i < (int)sizeof(ctx->buf)); memcpy(out, &(ctx->buf[ctx->buf_off]), i); ret = i; out += i; outl -= i; ctx->buf_off += i; if (ctx->buf_len == ctx->buf_off) { ctx->buf_len = 0; ctx->buf_off = 0; } } /* * At this point, we have room of outl bytes and an empty buffer, so we * should read in some more. */ ret_code = 0; while (outl > 0) { if (ctx->cont <= 0) break; i = BIO_read(next, &(ctx->tmp[ctx->tmp_len]), B64_BLOCK_SIZE - ctx->tmp_len); if (i <= 0) { ret_code = i; /* Should we continue next time we are called? */ if (!BIO_should_retry(next)) { ctx->cont = i; /* If buffer empty break */ if (ctx->tmp_len == 0) break; /* Fall through and process what we have */ else i = 0; } /* else we retry and add more data to buffer */ else break; } i += ctx->tmp_len; ctx->tmp_len = i; /* * We need to scan, a line at a time until we have a valid line if we * are starting. */ if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) { /* ctx->start=1; */ ctx->tmp_len = 0; } else if (ctx->start) { q = p = (unsigned char *)ctx->tmp; num = 0; for (j = 0; j < i; j++) { if (*(q++) != '\n') continue; /* * due to a previous very long line, we need to keep on * scanning for a '\n' before we even start looking for * base64 encoded stuff. */ if (ctx->tmp_nl) { p = q; ctx->tmp_nl = 0; continue; } k = EVP_DecodeUpdate(ctx->base64, (unsigned char *)ctx->buf, &num, p, q - p); if ((k <= 0) && (num == 0) && (ctx->start)) EVP_DecodeInit(ctx->base64); else { if (p != (unsigned char *) &(ctx->tmp[0])) { i -= (p - (unsigned char *) &(ctx->tmp[0])); for (x = 0; x < i; x++) ctx->tmp[x] = p[x]; } EVP_DecodeInit(ctx->base64); ctx->start = 0; break; } p = q; } /* we fell off the end without starting */ if ((j == i) && (num == 0)) { /* * Is this is one long chunk?, if so, keep on reading until a * new line. */ if (p == (unsigned char *)&(ctx->tmp[0])) { /* Check buffer full */ if (i == B64_BLOCK_SIZE) { ctx->tmp_nl = 1; ctx->tmp_len = 0; } } else if (p != q) { /* finished on a '\n' */ n = q - p; for (ii = 0; ii < n; ii++) ctx->tmp[ii] = p[ii]; ctx->tmp_len = n; } /* else finished on a '\n' */ continue; } else { ctx->tmp_len = 0; } } else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0)) { /* * If buffer isn't full and we can retry then restart to read in * more data. */ continue; } if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { int z, jj; jj = i & ~3; /* process per 4 */ z = EVP_DecodeBlock((unsigned char *)ctx->buf, (unsigned char *)ctx->tmp, jj); if (jj > 2) { if (ctx->tmp[jj - 1] == '=') { z--; if (ctx->tmp[jj - 2] == '=') z--; } } /* * z is now number of output bytes and jj is the number consumed */ if (jj != i) { memmove(ctx->tmp, &ctx->tmp[jj], i - jj); ctx->tmp_len = i - jj; } ctx->buf_len = 0; if (z > 0) { ctx->buf_len = z; } i = z; } else { i = EVP_DecodeUpdate(ctx->base64, (unsigned char *)ctx->buf, &ctx->buf_len, (unsigned char *)ctx->tmp, i); ctx->tmp_len = 0; } /* * If eof or an error was signalled, then the condition * 'ctx->cont <= 0' will prevent b64_read() from reading * more data on subsequent calls. This assignment was * deleted accidentally in commit 5562cfaca4f3. */ ctx->cont = i; ctx->buf_off = 0; if (i < 0) { ret_code = 0; ctx->buf_len = 0; break; } if (ctx->buf_len <= outl) i = ctx->buf_len; else i = outl; memcpy(out, ctx->buf, i); ret += i; ctx->buf_off = i; if (ctx->buf_off == ctx->buf_len) { ctx->buf_len = 0; ctx->buf_off = 0; } outl -= i; out += i; } /* BIO_clear_retry_flags(b); */ BIO_copy_next_retry(b); return ((ret == 0) ? ret_code : ret); }
static int ok_write(BIO *b, const char *in, int inl) { int ret = 0, n, i; BIO_OK_CTX *ctx; BIO *next; if (inl <= 0) return inl; ctx = BIO_get_data(b); next = BIO_next(b); ret = inl; if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0)) return 0; if (ctx->sigio && !sig_out(b)) return 0; do { BIO_clear_retry_flags(b); n = ctx->buf_len - ctx->buf_off; while (ctx->blockout && n > 0) { i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n); if (i <= 0) { BIO_copy_next_retry(b); if (!BIO_should_retry(b)) ctx->cont = 0; return i; } ctx->buf_off += i; n -= i; } /* at this point all pending data has been written */ ctx->blockout = 0; if (ctx->buf_len == ctx->buf_off) { ctx->buf_len = OK_BLOCK_BLOCK; ctx->buf_off = 0; } if ((in == NULL) || (inl <= 0)) return 0; n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ? (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl; memcpy(&ctx->buf[ctx->buf_len], in, n); ctx->buf_len += n; inl -= n; in += n; if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) { if (!block_out(b)) { BIO_clear_retry_flags(b); return 0; } } } while (inl > 0); BIO_clear_retry_flags(b); BIO_copy_next_retry(b); return ret; }
static int b64_write(BIO *b, const char *in, int inl) { int ret = 0; int n; int i; BIO_B64_CTX *ctx; BIO *next; ctx = (BIO_B64_CTX *)BIO_get_data(b); next = BIO_next(b); if ((ctx == NULL) || (next == NULL)) return 0; BIO_clear_retry_flags(b); if (ctx->encode != B64_ENCODE) { ctx->encode = B64_ENCODE; ctx->buf_len = 0; ctx->buf_off = 0; ctx->tmp_len = 0; EVP_EncodeInit(ctx->base64); } OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf)); OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); OPENSSL_assert(ctx->buf_len >= ctx->buf_off); n = ctx->buf_len - ctx->buf_off; while (n > 0) { i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n); if (i <= 0) { BIO_copy_next_retry(b); return i; } OPENSSL_assert(i <= n); ctx->buf_off += i; OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); OPENSSL_assert(ctx->buf_len >= ctx->buf_off); n -= i; } /* at this point all pending data has been written */ ctx->buf_off = 0; ctx->buf_len = 0; if ((in == NULL) || (inl <= 0)) return 0; while (inl > 0) { n = (inl > B64_BLOCK_SIZE) ? B64_BLOCK_SIZE : inl; if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { if (ctx->tmp_len > 0) { OPENSSL_assert(ctx->tmp_len <= 3); n = 3 - ctx->tmp_len; /* * There's a theoretical possibility for this */ if (n > inl) n = inl; memcpy(&(ctx->tmp[ctx->tmp_len]), in, n); ctx->tmp_len += n; ret += n; if (ctx->tmp_len < 3) break; ctx->buf_len = EVP_EncodeBlock((unsigned char *)ctx->buf, (unsigned char *)ctx->tmp, ctx->tmp_len); OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); OPENSSL_assert(ctx->buf_len >= ctx->buf_off); /* * Since we're now done using the temporary buffer, the * length should be 0'd */ ctx->tmp_len = 0; } else { if (n < 3) { memcpy(ctx->tmp, in, n); ctx->tmp_len = n; ret += n; break; } n -= n % 3; ctx->buf_len = EVP_EncodeBlock((unsigned char *)ctx->buf, (const unsigned char *)in, n); OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); OPENSSL_assert(ctx->buf_len >= ctx->buf_off); ret += n; } } else { if (!EVP_EncodeUpdate(ctx->base64, (unsigned char *)ctx->buf, &ctx->buf_len, (unsigned char *)in, n)) return ((ret == 0) ? -1 : ret); OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); OPENSSL_assert(ctx->buf_len >= ctx->buf_off); ret += n; } inl -= n; in += n; ctx->buf_off = 0; n = ctx->buf_len; while (n > 0) { i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n); if (i <= 0) { BIO_copy_next_retry(b); return ((ret == 0) ? i : ret); } OPENSSL_assert(i <= n); n -= i; ctx->buf_off += i; OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); OPENSSL_assert(ctx->buf_len >= ctx->buf_off); } ctx->buf_len = 0; ctx->buf_off = 0; } return ret; }
static int test_dtls_unprocessed(int testidx) { SSL_CTX *sctx = NULL, *cctx = NULL; SSL *serverssl1 = NULL, *clientssl1 = NULL; BIO *c_to_s_fbio, *c_to_s_mempacket; int testresult = 0; timer_cb_count = 0; if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), DTLS_client_method(), DTLS1_VERSION, DTLS_MAX_VERSION, &sctx, &cctx, cert, privkey))) return 0; if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "AES128-SHA"))) goto end; c_to_s_fbio = BIO_new(bio_f_tls_dump_filter()); if (!TEST_ptr(c_to_s_fbio)) goto end; /* BIO is freed by create_ssl_connection on error */ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1, NULL, c_to_s_fbio))) goto end; DTLS_set_timer_cb(clientssl1, timer_cb); if (testidx == 1) certstatus[RECORD_SEQUENCE] = 0xff; /* * Inject a dummy record from the next epoch. In test 0, this should never * get used because the message sequence number is too big. In test 1 we set * the record sequence number to be way off in the future. This should not * have an impact on the record replay protection because the record should * be dropped before it is marked as arrived */ c_to_s_mempacket = SSL_get_wbio(clientssl1); c_to_s_mempacket = BIO_next(c_to_s_mempacket); mempacket_test_inject(c_to_s_mempacket, (char *)certstatus, sizeof(certstatus), 1, INJECT_PACKET_IGNORE_REC_SEQ); if (!TEST_true(create_ssl_connection(serverssl1, clientssl1, SSL_ERROR_NONE))) goto end; if (timer_cb_count == 0) { printf("timer_callback was not called.\n"); goto end; } testresult = 1; end: SSL_free(serverssl1); SSL_free(clientssl1); SSL_CTX_free(sctx); SSL_CTX_free(cctx); return testresult; }
static long b64_ctrl(BIO *b, int cmd, long num, void *ptr) { BIO_B64_CTX *ctx; long ret = 1; int i; BIO *next; ctx = (BIO_B64_CTX *)BIO_get_data(b); next = BIO_next(b); if ((ctx == NULL) || (next == NULL)) return 0; switch (cmd) { case BIO_CTRL_RESET: ctx->cont = 1; ctx->start = 1; ctx->encode = B64_NONE; ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_EOF: /* More to read */ if (ctx->cont <= 0) ret = 1; else ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_WPENDING: /* More to write in buffer */ OPENSSL_assert(ctx->buf_len >= ctx->buf_off); ret = ctx->buf_len - ctx->buf_off; if ((ret == 0) && (ctx->encode != B64_NONE) && (EVP_ENCODE_CTX_num(ctx->base64) != 0)) ret = 1; else if (ret <= 0) ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_PENDING: /* More to read in buffer */ OPENSSL_assert(ctx->buf_len >= ctx->buf_off); ret = ctx->buf_len - ctx->buf_off; if (ret <= 0) ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_FLUSH: /* do a final write */ again: while (ctx->buf_len != ctx->buf_off) { i = b64_write(b, NULL, 0); if (i < 0) return i; } if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { if (ctx->tmp_len != 0) { ctx->buf_len = EVP_EncodeBlock((unsigned char *)ctx->buf, (unsigned char *)ctx->tmp, ctx->tmp_len); ctx->buf_off = 0; ctx->tmp_len = 0; goto again; } } else if (ctx->encode != B64_NONE && EVP_ENCODE_CTX_num(ctx->base64) != 0) { ctx->buf_off = 0; EVP_EncodeFinal(ctx->base64, (unsigned char *)ctx->buf, &(ctx->buf_len)); /* push out the bytes */ goto again; } /* Finally flush the underlying BIO */ ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); ret = BIO_ctrl(next, cmd, num, ptr); BIO_copy_next_retry(b); break; case BIO_CTRL_DUP: break; case BIO_CTRL_INFO: case BIO_CTRL_GET: case BIO_CTRL_SET: default: ret = BIO_ctrl(next, cmd, num, ptr); break; } return ret; }
int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509) { ASN1_OCTET_STRING *os; EVP_MD_CTX mdc_tmp, *mdc; int ret = 0, i; int md_type; STACK_OF(X509_ATTRIBUTE) *sk; BIO *btmp; EVP_PKEY *pkey; EVP_MD_CTX_init(&mdc_tmp); if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); goto err; } md_type = OBJ_obj2nid(si->digest_alg->algorithm); btmp = bio; for (;;) { if ((btmp == NULL) || ((btmp = BIO_find_type(btmp, BIO_TYPE_MD)) == NULL)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } BIO_get_md_ctx(btmp, &mdc); if (mdc == NULL) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_INTERNAL_ERROR); goto err; } if (EVP_MD_CTX_type(mdc) == md_type) break; /* * Workaround for some broken clients that put the signature OID * instead of the digest OID in digest_alg->algorithm */ if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type) break; btmp = BIO_next(btmp); } /* * mdc is the digest ctx that we want, unless there are attributes, in * which case the digest is the signed attributes */ if (!EVP_MD_CTX_copy_ex(&mdc_tmp, mdc)) goto err; sk = si->auth_attr; if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL; unsigned int md_len; int alen; ASN1_OCTET_STRING *message_digest; if (!EVP_DigestFinal_ex(&mdc_tmp, md_dat, &md_len)) goto err; message_digest = PKCS7_digest_from_attributes(sk); if (!message_digest) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } if ((message_digest->length != (int)md_len) || (memcmp(message_digest->data, md_dat, md_len))) { #if 0 { int ii; for (ii = 0; ii < message_digest->length; ii++) printf("%02X", message_digest->data[ii]); printf(" sent\n"); for (ii = 0; ii < md_len; ii++) printf("%02X", md_dat[ii]); printf(" calc\n"); } #endif PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_DIGEST_FAILURE); ret = -1; goto err; } if (!EVP_VerifyInit_ex(&mdc_tmp, EVP_get_digestbynid(md_type), NULL)) goto err; alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf, ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY)); if (alen <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_ASN1_LIB); ret = -1; goto err; } if (!EVP_VerifyUpdate(&mdc_tmp, abuf, alen)) goto err; OPENSSL_free(abuf); } os = si->enc_digest; pkey = X509_get_pubkey(x509); if (!pkey) { ret = -1; goto err; } i = EVP_VerifyFinal(&mdc_tmp, os->data, os->length, pkey); EVP_PKEY_free(pkey); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); ret = -1; goto err; } else ret = 1; err: EVP_MD_CTX_cleanup(&mdc_tmp); return (ret); }
static int test_dtls_drop_records(int idx) { SSL_CTX *sctx = NULL, *cctx = NULL; SSL *serverssl = NULL, *clientssl = NULL; BIO *c_to_s_fbio, *mempackbio; int testresult = 0; int epoch = 0; SSL_SESSION *sess = NULL; int cli_to_srv_epoch0, cli_to_srv_epoch1, srv_to_cli_epoch0; if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), DTLS_client_method(), DTLS1_VERSION, DTLS_MAX_VERSION, &sctx, &cctx, cert, privkey))) return 0; if (idx >= TOTAL_FULL_HAND_RECORDS) { /* We're going to do a resumption handshake. Get a session first. */ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) || !TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) || !TEST_ptr(sess = SSL_get1_session(clientssl))) goto end; SSL_shutdown(clientssl); SSL_shutdown(serverssl); SSL_free(serverssl); SSL_free(clientssl); serverssl = clientssl = NULL; cli_to_srv_epoch0 = CLI_TO_SRV_RESUME_EPOCH_0_RECS; cli_to_srv_epoch1 = CLI_TO_SRV_RESUME_EPOCH_1_RECS; srv_to_cli_epoch0 = SRV_TO_CLI_RESUME_EPOCH_0_RECS; idx -= TOTAL_FULL_HAND_RECORDS; } else { cli_to_srv_epoch0 = CLI_TO_SRV_EPOCH_0_RECS; cli_to_srv_epoch1 = CLI_TO_SRV_EPOCH_1_RECS; srv_to_cli_epoch0 = SRV_TO_CLI_EPOCH_0_RECS; } c_to_s_fbio = BIO_new(bio_f_tls_dump_filter()); if (!TEST_ptr(c_to_s_fbio)) goto end; /* BIO is freed by create_ssl_connection on error */ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, c_to_s_fbio))) goto end; if (sess != NULL) { if (!TEST_true(SSL_set_session(clientssl, sess))) goto end; } DTLS_set_timer_cb(clientssl, timer_cb); DTLS_set_timer_cb(serverssl, timer_cb); /* Work out which record to drop based on the test number */ if (idx >= cli_to_srv_epoch0 + cli_to_srv_epoch1) { mempackbio = SSL_get_wbio(serverssl); idx -= cli_to_srv_epoch0 + cli_to_srv_epoch1; if (idx >= srv_to_cli_epoch0) { epoch = 1; idx -= srv_to_cli_epoch0; } } else { mempackbio = SSL_get_wbio(clientssl); if (idx >= cli_to_srv_epoch0) { epoch = 1; idx -= cli_to_srv_epoch0; } mempackbio = BIO_next(mempackbio); } BIO_ctrl(mempackbio, MEMPACKET_CTRL_SET_DROP_EPOCH, epoch, NULL); BIO_ctrl(mempackbio, MEMPACKET_CTRL_SET_DROP_REC, idx, NULL); if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) goto end; if (sess != NULL && !TEST_true(SSL_session_reused(clientssl))) goto end; /* If the test did what we planned then it should have dropped a record */ if (!TEST_int_eq((int)BIO_ctrl(mempackbio, MEMPACKET_CTRL_GET_DROP_REC, 0, NULL), -1)) goto end; testresult = 1; end: SSL_SESSION_free(sess); SSL_free(serverssl); SSL_free(clientssl); SSL_CTX_free(sctx); SSL_CTX_free(cctx); return testresult; }