static int mempacket_test_read(BIO *bio, char *out, int outl) { MEMPACKET_TEST_CTX *ctx = bio->ptr; MEMPACKET *thispkt; uint8_t *rec; int rem; unsigned int seq, offset, len, epoch; BIO_clear_retry_flags(bio); thispkt = sk_MEMPACKET_value(ctx->pkts, 0); if (thispkt == NULL || thispkt->num != ctx->currpkt) { /* Probably run out of data */ BIO_set_retry_read(bio); return -1; } sk_MEMPACKET_shift(ctx->pkts); ctx->currpkt++; if (outl > thispkt->len) outl = thispkt->len; if (thispkt->type != INJECT_PACKET_IGNORE_REC_SEQ) { /* * Overwrite the record sequence number. We strictly number them in * the order received. Since we are actually a reliable transport * we know that there won't be any re-ordering. We overwrite to deal * with any packets that have been injected */ rem = thispkt->len; rec = thispkt->data; while (rem > 0) { if (rem < DTLS1_RT_HEADER_LENGTH) { return -1; } epoch = (rec[EPOCH_HI] << 8) | rec[EPOCH_LO]; if (epoch != ctx->epoch) { ctx->epoch = epoch; ctx->currrec = 0; } seq = ctx->currrec; offset = 0; do { rec[RECORD_SEQUENCE - offset] = seq & 0xFF; seq >>= 8; offset++; } while (seq > 0); ctx->currrec++; len = ((rec[RECORD_LEN_HI] << 8) | rec[RECORD_LEN_LO]) + DTLS1_RT_HEADER_LENGTH; rec += len; rem -= len; } }
static long mempacket_test_ctrl(BIO *bio, int cmd, long num, void *ptr) { long ret = 1; MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio); MEMPACKET *thispkt; switch (cmd) { case BIO_CTRL_EOF: ret = (long)(sk_MEMPACKET_num(ctx->pkts) == 0); break; case BIO_CTRL_GET_CLOSE: ret = BIO_get_shutdown(bio); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(bio, (int)num); break; case BIO_CTRL_WPENDING: ret = 0L; break; case BIO_CTRL_PENDING: thispkt = sk_MEMPACKET_value(ctx->pkts, 0); if (thispkt == NULL) ret = 0; else ret = thispkt->len; break; case BIO_CTRL_FLUSH: ret = 1; break; case MEMPACKET_CTRL_SET_DROP_EPOCH: ctx->dropepoch = (unsigned int)num; break; case MEMPACKET_CTRL_SET_DROP_REC: ctx->droprec = (int)num; break; case MEMPACKET_CTRL_GET_DROP_REC: ret = ctx->droprec; break; case MEMPACKET_CTRL_SET_DUPLICATE_REC: ctx->duprec = (int)num; break; case BIO_CTRL_RESET: case BIO_CTRL_DUP: case BIO_CTRL_PUSH: case BIO_CTRL_POP: default: ret = 0; break; } return ret; }
int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum, int type) { MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio); MEMPACKET *thispkt, *looppkt, *nextpkt; int i; if (ctx == NULL) return -1; /* We only allow injection before we've started writing any data */ if (pktnum >= 0) { if (ctx->noinject) return -1; } else { ctx->noinject = 1; } if (!TEST_ptr(thispkt = OPENSSL_malloc(sizeof(*thispkt)))) return -1; if (!TEST_ptr(thispkt->data = OPENSSL_malloc(inl))) { mempacket_free(thispkt); return -1; } memcpy(thispkt->data, in, inl); thispkt->len = inl; thispkt->num = (pktnum >= 0) ? (unsigned int)pktnum : ctx->lastpkt; thispkt->type = type; for(i = 0; (looppkt = sk_MEMPACKET_value(ctx->pkts, i)) != NULL; i++) { /* Check if we found the right place to insert this packet */ if (looppkt->num > thispkt->num) { if (sk_MEMPACKET_insert(ctx->pkts, thispkt, i) == 0) { mempacket_free(thispkt); return -1; } /* If we're doing up front injection then we're done */ if (pktnum >= 0) return inl; /* * We need to do some accounting on lastpkt. We increment it first, * but it might now equal the value of injected packets, so we need * to skip over those */ ctx->lastpkt++; do { i++; nextpkt = sk_MEMPACKET_value(ctx->pkts, i); if (nextpkt != NULL && nextpkt->num == ctx->lastpkt) ctx->lastpkt++; else return inl; } while(1); } else if (looppkt->num == thispkt->num) { if (!ctx->noinject) { /* We injected two packets with the same packet number! */ return -1; } ctx->lastpkt++; thispkt->num++; } } /* * We didn't find any packets with a packet number equal to or greater than * this one, so we just add it onto the end */ if (!sk_MEMPACKET_push(ctx->pkts, thispkt)) { mempacket_free(thispkt); return -1; } if (pktnum < 0) ctx->lastpkt++; return inl; }
int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum, int type) { MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio); MEMPACKET *thispkt = NULL, *looppkt, *nextpkt, *allpkts[3]; int i, duprec = ctx->duprec > 0; const unsigned char *inu = (const unsigned char *)in; size_t len = ((inu[RECORD_LEN_HI] << 8) | inu[RECORD_LEN_LO]) + DTLS1_RT_HEADER_LENGTH; if (ctx == NULL) return -1; if ((size_t)inl < len) return -1; if ((size_t)inl == len) duprec = 0; /* We don't support arbitrary injection when duplicating records */ if (duprec && pktnum != -1) return -1; /* We only allow injection before we've started writing any data */ if (pktnum >= 0) { if (ctx->noinject) return -1; ctx->injected = 1; } else { ctx->noinject = 1; } for (i = 0; i < (duprec ? 3 : 1); i++) { if (!TEST_ptr(allpkts[i] = OPENSSL_malloc(sizeof(*thispkt)))) goto err; thispkt = allpkts[i]; if (!TEST_ptr(thispkt->data = OPENSSL_malloc(inl))) goto err; /* * If we are duplicating the packet, we duplicate it three times. The * first two times we drop the first record if there are more than one. * In this way we know that libssl will not be able to make progress * until it receives the last packet, and hence will be forced to * buffer these records. */ if (duprec && i != 2) { memcpy(thispkt->data, in + len, inl - len); thispkt->len = inl - len; } else { memcpy(thispkt->data, in, inl); thispkt->len = inl; } thispkt->num = (pktnum >= 0) ? (unsigned int)pktnum : ctx->lastpkt + i; thispkt->type = type; } for(i = 0; (looppkt = sk_MEMPACKET_value(ctx->pkts, i)) != NULL; i++) { /* Check if we found the right place to insert this packet */ if (looppkt->num > thispkt->num) { if (sk_MEMPACKET_insert(ctx->pkts, thispkt, i) == 0) goto err; /* If we're doing up front injection then we're done */ if (pktnum >= 0) return inl; /* * We need to do some accounting on lastpkt. We increment it first, * but it might now equal the value of injected packets, so we need * to skip over those */ ctx->lastpkt++; do { i++; nextpkt = sk_MEMPACKET_value(ctx->pkts, i); if (nextpkt != NULL && nextpkt->num == ctx->lastpkt) ctx->lastpkt++; else return inl; } while(1); } else if (looppkt->num == thispkt->num) { if (!ctx->noinject) { /* We injected two packets with the same packet number! */ goto err; } ctx->lastpkt++; thispkt->num++; } } /* * We didn't find any packets with a packet number equal to or greater than * this one, so we just add it onto the end */ for (i = 0; i < (duprec ? 3 : 1); i++) { thispkt = allpkts[i]; if (!sk_MEMPACKET_push(ctx->pkts, thispkt)) goto err; if (pktnum < 0) ctx->lastpkt++; } return inl; err: for (i = 0; i < (ctx->duprec > 0 ? 3 : 1); i++) mempacket_free(allpkts[i]); return -1; }
static int mempacket_test_read(BIO *bio, char *out, int outl) { MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio); MEMPACKET *thispkt; unsigned char *rec; int rem; unsigned int seq, offset, len, epoch; BIO_clear_retry_flags(bio); thispkt = sk_MEMPACKET_value(ctx->pkts, 0); if (thispkt == NULL || thispkt->num != ctx->currpkt) { /* Probably run out of data */ BIO_set_retry_read(bio); return -1; } (void)sk_MEMPACKET_shift(ctx->pkts); ctx->currpkt++; if (outl > thispkt->len) outl = thispkt->len; if (thispkt->type != INJECT_PACKET_IGNORE_REC_SEQ && (ctx->injected || ctx->droprec >= 0)) { /* * Overwrite the record sequence number. We strictly number them in * the order received. Since we are actually a reliable transport * we know that there won't be any re-ordering. We overwrite to deal * with any packets that have been injected */ for (rem = thispkt->len, rec = thispkt->data; rem > 0; rem -= len) { if (rem < DTLS1_RT_HEADER_LENGTH) return -1; epoch = (rec[EPOCH_HI] << 8) | rec[EPOCH_LO]; if (epoch != ctx->epoch) { ctx->epoch = epoch; ctx->currrec = 0; } seq = ctx->currrec; offset = 0; do { rec[RECORD_SEQUENCE - offset] = seq & 0xFF; seq >>= 8; offset++; } while (seq > 0); len = ((rec[RECORD_LEN_HI] << 8) | rec[RECORD_LEN_LO]) + DTLS1_RT_HEADER_LENGTH; if (rem < (int)len) return -1; if (ctx->droprec == (int)ctx->currrec && ctx->dropepoch == epoch) { if (rem > (int)len) memmove(rec, rec + len, rem - len); outl -= len; ctx->droprec = -1; if (outl == 0) BIO_set_retry_read(bio); } else { rec += len; } ctx->currrec++; } } memcpy(out, thispkt->data, outl); mempacket_free(thispkt); return outl; }