+ /*
+ * PS must be at least 8 bytes long, and it starts two bytes into |from|.
+ * If we never found a 0-byte, then |zero_index| is 0 and the check
+ * also fails.
+ */
+ good &= constant_time_ge(zero_index, 2 + 8);
+ err = constant_time_select_int(mask | good, err,
+ RSA_R_NULL_BEFORE_BLOCK_MISSING);
+ mask = ~good;
+
+ good &= constant_time_lt(threes_in_row, 8);
+ err = constant_time_select_int(mask | good, err,
+ RSA_R_SSLV3_ROLLBACK_ATTACK);
+ mask = ~good;
+
+ /*
+ * Skip the zero byte. This is incorrect if we never found a zero-byte
+ * but in this case we also do not copy the message out.
+ */
+ msg_index = zero_index + 1;
+ mlen = num - msg_index;
+
+ /*
+ * For good measure, do this check in constant time as well.
+ */
+ good &= constant_time_ge(tlen, mlen);
+ err = constant_time_select_int(mask | good, err, RSA_R_DATA_TOO_LARGE);
+
+ /*
+ * Even though we can't fake result's length, we can pretend copying
+ * |tlen| bytes where |mlen| bytes would be real. Last |tlen| of |num|
+ * bytes are viewed as circular buffer with start at |tlen|-|mlen'|,
+ * where |mlen'| is "saturated" |mlen| value. Deducing information
+ * about failure or |mlen| would take attacker's ability to observe
+ * memory access pattern with byte granularity *as it occurs*. It
+ * should be noted that failure is indistinguishable from normal
+ * operation if |tlen| is fixed by protocol.
+ */
+ tlen = constant_time_select_int(constant_time_lt(num, tlen), num, tlen);
+ msg_index = constant_time_select_int(good, msg_index, num - tlen);
+ mlen = num - msg_index;
+ for (from += msg_index, mask = good, i = 0; i < tlen; i++) {
+ unsigned int equals = constant_time_eq(i, mlen);
+
+ from -= tlen & equals; /* if (i == mlen) rewind */
+ mask &= mask ^ equals; /* if (i == mlen) mask = 0 */
+ to[i] = constant_time_select_8(mask, from[i], to[i]);