Skip to content

Commit e7ed802

Browse files
committed
Initial implementation of RSA X931 for wolfProvider
1 parent aad3272 commit e7ed802

File tree

1 file changed

+350
-1
lines changed

1 file changed

+350
-1
lines changed

src/wp_rsa_sig.c

Lines changed: 350 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,9 @@ static int wp_rsa_signverify_init(wp_RsaSigCtx* ctx, wp_Rsa* rsa,
469469
ctx->saltLen = RSA_PSS_SALTLEN_AUTO;
470470

471471
if (wp_rsa_get_type(ctx->rsa) == RSA_FLAG_TYPE_RSA) {
472-
ctx->padMode = RSA_PKCS1_PADDING;
472+
if (ctx->padMode != RSA_X931_PADDING) {
473+
ctx->padMode = RSA_PKCS1_PADDING;
474+
}
473475
}
474476
else {
475477
char* mdName;
@@ -651,6 +653,56 @@ static int wp_rsa_sign_pss(wp_RsaSigCtx* ctx, unsigned char* sig,
651653
return ok;
652654
}
653655

656+
/**
657+
* Add X9.31 padding to the input buffer, placing the result in the output
658+
* buffer.
659+
*
660+
* @param to [out] Buffer to store padded result.
661+
* @param toLen [in] Length of "to" buffer.
662+
* @param from [in] Input buffer.
663+
* @param fromLen [in] Length of input buffer.
664+
* @returns 1 on success and 0 on failure.
665+
*/
666+
static int wp_add_x931_padding(unsigned char* to, size_t toLen,
667+
const unsigned char* from, size_t fromLen)
668+
{
669+
int ok = 1;
670+
int padBytes;
671+
672+
if (to == NULL || from == NULL) {
673+
WOLFPROV_ERROR_MSG(WP_LOG_PK, "Bad argument.");
674+
ok = 0;
675+
}
676+
else {
677+
/* Need at least two bytes for trailer and header. */
678+
padBytes = (int)(toLen - fromLen - 2);
679+
if (padBytes < 0) {
680+
WOLFPROV_ERROR_MSG(WP_LOG_PK, "Output buffer too small.");
681+
ok = 0;
682+
}
683+
}
684+
685+
if (ok == 1) {
686+
if (padBytes == 0) {
687+
to[0] = 0x6A;
688+
}
689+
else {
690+
to[0] = 0x6B;
691+
if (padBytes > 1) {
692+
XMEMSET(&to[1], 0xBB, padBytes - 1);
693+
}
694+
to[padBytes] = 0xBA;
695+
}
696+
697+
XMEMCPY(&to[padBytes + 1], from, fromLen);
698+
to[toLen - 1] = 0xCC;
699+
}
700+
701+
WOLFPROV_LEAVE(WP_LOG_PK, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
702+
703+
return ok;
704+
}
705+
654706
/**
655707
* Sign the data using RSA without padding.
656708
*
@@ -691,6 +743,134 @@ static int wp_rsa_sign_no_pad(wp_RsaSigCtx* ctx, unsigned char* sig,
691743
return ok;
692744
}
693745

746+
static int wp_rsa_get_x931_hash_code(enum wc_HashType hash) {
747+
int ret = 0;
748+
749+
if (hash == WC_HASH_TYPE_SHA) {
750+
ret = 0x33;
751+
}
752+
else if (hash == WC_HASH_TYPE_SHA256) {
753+
ret = 0x34;
754+
}
755+
else if (hash == WC_HASH_TYPE_SHA384) {
756+
ret = 0x36;
757+
}
758+
else if (hash == WC_HASH_TYPE_SHA512) {
759+
ret = 0x35;
760+
}
761+
762+
return ret;
763+
}
764+
765+
/**
766+
* Sign the data using RSA with X931 padding.
767+
*
768+
* @param [in, out] ctx RSA signature context object.
769+
* @param [out] sig Buffer to hold signature.
770+
* @param [out] sigLen Length of signature data in bytes.
771+
* @param [in] sigSize Size of signature buffer in bytes.
772+
* @param [in] tbs Data to be signed.
773+
* @param [in] tbsLen Length of data to be signed in bytes.
774+
* @return 1 on success.
775+
* @return 0 on failure.
776+
*/
777+
static int wp_rsa_sign_x931(wp_RsaSigCtx* ctx, unsigned char* sig,
778+
size_t* sigLen, size_t sigSize, const unsigned char* tbs, size_t tbsLen)
779+
{
780+
int ok = 1;
781+
int paddedSz = 0;
782+
unsigned char *padded = NULL;
783+
unsigned char *tbuf = NULL;
784+
int rc = 0;
785+
mp_int toMp;
786+
mp_int nMinusTo;
787+
788+
paddedSz = wc_RsaEncryptSize(wp_rsa_get_key(ctx->rsa));
789+
if (paddedSz <= 0) {
790+
ok = 0;
791+
}
792+
if (ok) {
793+
tbuf = (unsigned char *)OPENSSL_malloc(paddedSz);
794+
if (tbuf == NULL) {
795+
ok = 0;
796+
}
797+
}
798+
if (ok) {
799+
padded = (unsigned char *)OPENSSL_malloc(paddedSz);
800+
if (padded == NULL) {
801+
ok = 0;
802+
}
803+
}
804+
if (ok) {
805+
XMEMCPY(tbuf, tbs, tbsLen);
806+
tbuf[tbsLen] = wp_rsa_get_x931_hash_code(
807+
#if LIBWOLFSSL_VERSION_HEX >= 0x05007004
808+
ctx->hash.type
809+
#else
810+
ctx->hashType
811+
#endif
812+
);
813+
}
814+
if (ok) {
815+
if (wp_add_x931_padding(padded, paddedSz, tbuf, tbsLen + 1) != 1) {
816+
ok = 0;
817+
}
818+
}
819+
if (ok) {
820+
word32 len = (word32)sigSize;
821+
822+
PRIVATE_KEY_UNLOCK();
823+
rc = wc_RsaDirect(padded, paddedSz, sig, &len,
824+
wp_rsa_get_key(ctx->rsa), RSA_PRIVATE_ENCRYPT, &ctx->rng);
825+
PRIVATE_KEY_LOCK();
826+
if (rc < 0) {
827+
ok = 0;
828+
}
829+
else {
830+
*sigLen = rc;
831+
}
832+
}
833+
if (padded != NULL) {
834+
OPENSSL_free(padded);
835+
}
836+
if (tbuf != NULL) {
837+
OPENSSL_free(tbuf);
838+
}
839+
if (ok) {
840+
rc = mp_init_multi(&toMp, &nMinusTo, NULL, NULL, NULL, NULL);
841+
if (rc != MP_OKAY) {
842+
ok = 0;
843+
}
844+
}
845+
if (ok) {
846+
rc = mp_read_unsigned_bin(&toMp, sig, *sigLen);
847+
if (rc != MP_OKAY) {
848+
ok = 0;
849+
}
850+
}
851+
if (ok) {
852+
/*
853+
* X9.31 specifies, "The signature is either the result
854+
* or its complement to n, whichever is smaller."
855+
*/
856+
rc = mp_sub(&(wp_rsa_get_key(ctx->rsa)->n), &toMp, &nMinusTo);
857+
if (rc != MP_OKAY) {
858+
ok = 0;
859+
}
860+
else if (mp_cmp(&toMp, &nMinusTo) == MP_GT) {
861+
rc = mp_to_unsigned_bin(&nMinusTo, sig);
862+
if (rc != MP_OKAY) {
863+
ok = 0;
864+
}
865+
}
866+
}
867+
mp_free(&toMp);
868+
mp_free(&nMinusTo);
869+
870+
WOLFPROV_LEAVE(WP_LOG_PK, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
871+
return ok;
872+
}
873+
694874
/**
695875
* Sign the data using an RSA key.
696876
*
@@ -733,6 +913,9 @@ static int wp_rsa_sign(wp_RsaSigCtx* ctx, unsigned char* sig, size_t* sigLen,
733913
else if (ctx->padMode == RSA_NO_PADDING) {
734914
ok = wp_rsa_sign_no_pad(ctx, sig, sigLen, sigSize, tbs, tbsLen);
735915
}
916+
else if (ctx->padMode == RSA_X931_PADDING) {
917+
ok = wp_rsa_sign_x931(ctx, sig, sigLen, sigSize, tbs, tbsLen);
918+
}
736919
else {
737920
ok = 0;
738921
}
@@ -929,6 +1112,163 @@ static int wp_rsa_verify_no_pad(wp_RsaSigCtx* ctx, const unsigned char* sig,
9291112
return ok;
9301113
}
9311114

1115+
/**
1116+
* Remove X9.31 padding from the input buffer, placing the result in the output
1117+
* buffer.
1118+
*
1119+
* @param to [out] Pointer to buffer holding unpadded result. This
1120+
* buffer will be allocated by this function if *to is
1121+
* NULL.
1122+
* @param from [in] Input buffer.
1123+
* @param fromLen [in] Length of input buffer.
1124+
* @returns Length of unpadded result on success and -1 on failure.
1125+
*/
1126+
static int wp_remove_x931_padding(unsigned char** to, const unsigned char* from,
1127+
size_t fromLen)
1128+
{
1129+
int ret = -1;
1130+
int ok = 1;
1131+
size_t idx = 0;
1132+
size_t numCopy = 0;
1133+
1134+
if (to == NULL || from == NULL || fromLen < 2) {
1135+
ok = 0;
1136+
}
1137+
else {
1138+
if (from[fromLen - 1] != 0xCC) {
1139+
ok = 0;
1140+
}
1141+
1142+
if (from[idx] == 0x6B) {
1143+
while (++idx < fromLen && from[idx] == 0xBB) {}
1144+
1145+
if (idx == fromLen || from[idx] != 0xBA) {
1146+
ok = 0;
1147+
}
1148+
}
1149+
else if (from[idx] != 0x6A) {
1150+
ok = 0;
1151+
}
1152+
}
1153+
1154+
if (ok) {
1155+
++idx;
1156+
numCopy = fromLen - idx - 1;
1157+
if (numCopy > 0) {
1158+
if (*to == NULL) {
1159+
*to = (unsigned char*)OPENSSL_malloc(numCopy);
1160+
if (*to == NULL) {
1161+
ok = 0;
1162+
}
1163+
}
1164+
if (ok){
1165+
XMEMCPY(*to, from + idx, numCopy);
1166+
}
1167+
}
1168+
}
1169+
1170+
if (ok) {
1171+
ret = (int)numCopy;
1172+
}
1173+
1174+
WOLFPROV_LEAVE(WP_LOG_PK, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ret);
1175+
return ret;
1176+
}
1177+
1178+
/**
1179+
* Verify an RSA X931 padded signature.
1180+
*
1181+
* @param [in] ctx RSA signature context object.
1182+
* @param [in] sig Signature data.
1183+
* @param [in] sigLen Length of signature data in bytes.
1184+
* @param [in] tbs Data to be signed.
1185+
* @param [in] tbsLen Length of data to be signed in bytes.
1186+
* @param [in] decryptedSig Buffer to hold decrypted signature.
1187+
* @return 1 on success.
1188+
* @return 0 on failure.
1189+
*/
1190+
static int wp_rsa_verify_x931(wp_RsaSigCtx* ctx, const unsigned char* sig,
1191+
size_t sigLen, const unsigned char* tbs, size_t tbsLen,
1192+
unsigned char* decryptedSig)
1193+
{
1194+
int ok = 1;
1195+
int rc;
1196+
word32 len = (word32)sigLen;
1197+
unsigned char* unpadded = NULL;
1198+
mp_int toMp;
1199+
mp_int nMinusTo;
1200+
1201+
rc = wc_RsaDirect((byte*)sig, (word32)sigLen, decryptedSig, &len,
1202+
wp_rsa_get_key(ctx->rsa), RSA_PUBLIC_DECRYPT, &ctx->rng);
1203+
if (rc < 0) {
1204+
ok = 0;
1205+
}
1206+
if (ok) {
1207+
/*
1208+
* X9.31 specifies, "If e is odd, then
1209+
* - If RR = 12 mod 16, then IR = RR ;
1210+
* - If n - RR = 12 mod 16, then IR = n - RR ;"
1211+
* RR is "to" and IR is the value to unpad in the next
1212+
* step. Taking "to" mod 16 is the same as just checking the
1213+
* lower 4 bits of "to."
1214+
*/
1215+
if ((decryptedSig[sigLen-1] & 0x0F) != 12) {
1216+
rc = mp_init_multi(&toMp, &nMinusTo, NULL, NULL, NULL, NULL);
1217+
if (rc != MP_OKAY) {
1218+
ok = 0;
1219+
}
1220+
if (ok) {
1221+
rc = mp_read_unsigned_bin(&toMp, decryptedSig, (int)sigLen);
1222+
if (rc != MP_OKAY) {
1223+
ok = 0;
1224+
} else {
1225+
rc = mp_sub(&(wp_rsa_get_key(ctx->rsa)->n), &toMp, &nMinusTo);
1226+
if (rc != MP_OKAY) {
1227+
ok = 0;
1228+
} else {
1229+
rc = mp_to_unsigned_bin(&nMinusTo, decryptedSig);
1230+
if (rc != MP_OKAY) {
1231+
ok = 0;
1232+
}
1233+
}
1234+
}
1235+
}
1236+
mp_free(&toMp);
1237+
mp_free(&nMinusTo);
1238+
}
1239+
}
1240+
if (ok) {
1241+
rc = wp_remove_x931_padding(&unpadded, decryptedSig, len);
1242+
if (rc <= 0) {
1243+
ok = 0;
1244+
} else {
1245+
XMEMCPY(decryptedSig, unpadded, rc);
1246+
rc--;
1247+
}
1248+
}
1249+
if (ok) {
1250+
if (unpadded[rc] != wp_rsa_get_x931_hash_code(
1251+
#if LIBWOLFSSL_VERSION_HEX >= 0x05007004
1252+
ctx->hash.type
1253+
#else
1254+
ctx->hashType
1255+
#endif
1256+
)) {
1257+
ok = 0;
1258+
}
1259+
}
1260+
if (ok && (((size_t)rc != tbsLen) || ((XMEMCMP(tbs, decryptedSig,
1261+
tbsLen) != 0)))) {
1262+
ok = 0;
1263+
}
1264+
if (NULL != unpadded) {
1265+
OPENSSL_free(unpadded);
1266+
}
1267+
1268+
WOLFPROV_LEAVE(WP_LOG_PK, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
1269+
return ok;
1270+
}
1271+
9321272
/**
9331273
* Verify an RSA signature.
9341274
*
@@ -970,6 +1310,10 @@ static int wp_rsa_verify(wp_RsaSigCtx* ctx, const unsigned char* sig,
9701310
ok = wp_rsa_verify_no_pad(ctx, sig, sigLen, tbs, tbsLen,
9711311
decryptedSig);
9721312
}
1313+
else if (ctx->padMode == RSA_X931_PADDING) {
1314+
ok = wp_rsa_verify_x931(ctx, sig, sigLen, tbs, tbsLen,
1315+
decryptedSig);
1316+
}
9731317
else {
9741318
ok = 0;
9751319
}
@@ -1517,6 +1861,11 @@ static int wp_rsa_set_pad_mode(wp_RsaSigCtx* ctx, const OSSL_PARAM* p)
15171861
ok = 0;
15181862
}
15191863
}
1864+
else if (padMode == RSA_X931_PADDING) {
1865+
if (wp_rsa_get_type(ctx->rsa) != RSA_FLAG_TYPE_RSA) {
1866+
ok = 0;
1867+
}
1868+
}
15201869
else {
15211870
ok = 0;
15221871
}

0 commit comments

Comments
 (0)