1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
|
/**************************************************************************
*** COPYRIGHT (c) 2002 by TransNexus, Inc. ***
*** ***
*** This software is property of TransNexus, Inc. ***
*** This software is freely available under license from TransNexus. ***
*** The license terms and conditions for free use of this software by ***
*** third parties are defined in the OSP Toolkit Software License ***
*** Agreement (LICENSE.txt). Any use of this software by third ***
*** parties, which does not comply with the terms and conditions of the ***
*** OSP Toolkit Software License Agreement is prohibited without ***
*** the prior, express, written consent of TransNexus, Inc. ***
*** ***
*** Thank you for using the OSP ToolKit(TM). Please report any bugs, ***
*** suggestions or feedback to support@transnexus.com ***
*** ***
**************************************************************************/
#include "osp/ospcomm.h"
#include "osp/ospssl.h"
#include "osp/ospsecurity.h"
#include "osp/ospb64.h"
#include "osptnep.h"
#include "osptnepinit.h"
#include "osp/ospcryptowrap.h"
/*
* Initialize the Enrollment Parameter object sent in. All of the
* structures will have to be malloced in this case.
*
* Input: Pointer to an OSPTENROLLPARAMS object
*
* Errors:
* o the pointer to the OSPTENROLLPARAMS is null;
* o malloc or initialization fails on any member of the OSPTENROLLPARAMS.
*/
int OSPPInitEnrollParams(OSPTENROLLPARAMS *ospvEnrollParamsIn)
{
int retVal = OSPC_ERR_NO_ERROR;
OSPM_DBGENTER(("ENTER: OSPPInitEnrollParams\n"));
/*
* If ( the pointer to the enrollment parameter list is ok ) then
* o allocate memory for every string in the enrollment parameter list
* using default lengths. If a string is too short, too long, or needs
* to be allocated in another function for some other reason, then
* just take it out here.
* o if ( all of the pointers are ok ) then
* - initialize all of their values.
*/
if (ospvEnrollParamsIn == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "Unable to initialize a null enrollment parameter set.\n");
}
if (retVal == OSPC_ERR_NO_ERROR) {
ospvEnrollParamsIn->Verbose = 0;
ospvEnrollParamsIn->Nonce = OSPC_OSNULL;
ospvEnrollParamsIn->NonceLen = 0;
ospvEnrollParamsIn->CACert = OSPC_OSNULL;
ospvEnrollParamsIn->CACertLen = 0;
ospvEnrollParamsIn->CACertB64 = OSPC_OSNULL;
ospvEnrollParamsIn->CACertB64Len = 0;
ospvEnrollParamsIn->Function = OSPC_OSNULL;
ospvEnrollParamsIn->Username = OSPC_OSNULL;
ospvEnrollParamsIn->Password = OSPC_OSNULL;
ospvEnrollParamsIn->DeviceId = OSPC_OSNULL;
ospvEnrollParamsIn->CustomerId = OSPC_OSNULL;
ospvEnrollParamsIn->CertReq = OSPC_OSNULL;
ospvEnrollParamsIn->SSLUrl = OSPC_OSNULL;
ospvEnrollParamsIn->CAUrl = OSPC_OSNULL;
ospvEnrollParamsIn->CAFprint = OSPC_OSNULL;
}
OSPM_DBGEXIT(("EXIT: OSPPFreeEnrollParams\n"));
return retVal;
}
/*
* This function is called for freeing up all the memory taken up
* by an enrollment parameter object.
*
* Input:
* o pointer to an OSPTENROLLPARAMS;
*
* Errors:
* o if the input variable is null ( OSPC_ERR_ENROLL_ENROLL_PARAMS_FREE )
*/
int OSPPFreeEnrollParams(OSPTENROLLPARAMS *ospvEnrollParamsIn)
{
int retVal = OSPC_ERR_NO_ERROR;
OSPM_DBGENTER(("ENTER: OSPPFreeEnrollParams\n"));
if (ospvEnrollParamsIn == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The enrollment parameter list being freed was null.\n");
}
/*
* Free all of the parameters in the enrollment list, just so long as
* they're valid ( and the enrollment list itself isn't null, either ):
*/
if (retVal == OSPC_ERR_NO_ERROR) {
if (ospvEnrollParamsIn->Function != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->Function);
}
if (ospvEnrollParamsIn->Username != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->Username);
}
if (ospvEnrollParamsIn->Password != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->Password);
}
if (ospvEnrollParamsIn->DeviceId != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->DeviceId);
}
if (ospvEnrollParamsIn->CustomerId != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->CustomerId);
}
if (ospvEnrollParamsIn->CertReq != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->CertReq);
}
if (ospvEnrollParamsIn->CAFprint != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->CAFprint);
}
if (ospvEnrollParamsIn->SSLUrl != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->SSLUrl);
}
if (ospvEnrollParamsIn->CAUrl != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->CAUrl);
}
if (ospvEnrollParamsIn->CACertB64 != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->CACertB64);
}
if (ospvEnrollParamsIn->CACert != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->CACert);
}
if (ospvEnrollParamsIn->Nonce != OSPC_OSNULL) {
OSPM_FREE(ospvEnrollParamsIn->Nonce);
}
}
OSPM_DBGEXIT(("EXIT: OSPPFreeEnrollParams\n"));
return retVal;
}
/*
* This function will take a list of enrollment parameters and communications
* parameters that specify how a communications manager will be set up.
* The communications manager will first be created and then initialized
* with all of the non-SSL-related parameters, followed by all of the
* SSL-related parameters.
*
* Input: a pointer to the enrollment server parameters ( for the enrollment
* server's url ); a pointer to the communication parameters; and a
* pointer to the reference to the communication manager to be initialized.
* *ospvCommOut should be null ( but ospvCommOut should not. )
*
* Output: *ospvCommMgrOut should be initialized as a communications manager.
* If it can't be initialized, then it should be null and the
* return value will be non-zero. Otherwise, the return value should
* be zero.
*/
int OSPPInitSecureCommMgr(OSPTENROLLPARAMS *ospvEnrollParamsIn,
OSPTCOMMPARAMS *ospvCommParamsIn,
OSPTCOMM **ospvCommOut)
{
int retVal = OSPC_ERR_NO_ERROR;
OSPM_DBGENTER(("ENTER: OSPPInitSecureCommMgr\n"));
/*
* If ( any of the parameters are null or
* if the url for the CA is null ) then
* o set an error code and complain.
*/
if ((ospvEnrollParamsIn == OSPC_OSNULL) || (ospvCommParamsIn == OSPC_OSNULL) || (ospvCommOut == OSPC_OSNULL) ||
(ospvEnrollParamsIn->SSLUrl == OSPC_OSNULL))
{
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The parameters for initializing the secure comm manager are invalid.\n");
}
/*
* Now create the communications manager. We should check the
* pointer returned for the communications manager even if the return
* value says otherwise.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPCommNew(ospvCommOut);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to allocate the space for the communications manager.\n");
} else if (*ospvCommOut == OSPC_OSNULL) {
retVal = OSPC_ERR_COMM_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "The communications manager returned was invalid.\n");
}
}
/* Initialize the communications manager, which includes allocating
* its memory.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPInitNonSSLCommMgrParams(ospvEnrollParamsIn->SSLUrl, ospvCommParamsIn, *ospvCommOut);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to initialize the communication manager's non-SSL related parameters.\n");
}
}
/* Now set up all of the communications parameters specific to SSL: */
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPInitSSLCommMgrParams(ospvEnrollParamsIn, ospvCommParamsIn, *ospvCommOut);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to initialize the communication manager's SSL related parameters.\n");
}
}
OSPM_DBGEXIT(("EXIT: OSPPInitSecureCommMgr\n"));
return retVal;
}
/*
* This is just a minimal wrapper for calling OSPPInitNonSecureCommMgrParams;
* it just extracts the service point for the CA from the enrollment
* parameters and passes it along as the service point to be explicitly
* contacted by the communications manager.
*
* Input: a pointer to the enrollment server parameters ( for the CA's
* url ); a pointer to the communication parameters; and a pointer
* to the reference to the communication manager to be initialized.
*
* Output: *ospvCommMgrOut should be initialized as a communications manager.
* If it can't be initialized, then it should be null and the
* return value will be non-zero. Otherwise, the return value should
* be zero.
*/
int OSPPInitNonSecureCommMgr(OSPTENROLLPARAMS *ospvEnrollParamsIn,
OSPTCOMMPARAMS *ospvCommParamsIn,
OSPTCOMM **ospvCommOut)
{
int retVal = OSPC_ERR_NO_ERROR;
OSPM_DBGENTER(("OSPPInitNonSecureCommMgr\n"));
/*
* If ( any of the parameters are null or
* if the url for the CA is null ) then
* o set an error code and complain.
*/
if ((ospvEnrollParamsIn == OSPC_OSNULL) || (ospvCommParamsIn == OSPC_OSNULL) || (ospvCommOut == OSPC_OSNULL) ||
(ospvEnrollParamsIn->CAUrl == OSPC_OSNULL))
{
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The parameters for initializing the CA's communications manager are invalid.\n");
}
/* Create the communications manager before we initialize it: */
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPCommNew(ospvCommOut);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to create communications manager\n");
}
/*
* For some reason we got a valid return value but an invalid
* communications manager; set an error code and complain:
*/
else if (*ospvCommOut == OSPC_OSNULL) {
retVal = OSPC_ERR_COMM_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "The communications manager returned was invalid.\n");
}
}
/*
* Now that the communications manager has been created, initialize
* its basic parameters. We'll use the CAUrl from the enrollment
* parameters as the service point:
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPInitNonSSLCommMgrParams(ospvEnrollParamsIn->CAUrl, ospvCommParamsIn, *ospvCommOut);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to initialize the communication manager's parameters for the CA.\n");
}
}
OSPM_DBGEXIT(("OSPPInitNonSecureCommMgr\n"));
return retVal;
}
/*
* Initialize the communications manager's SSL-related parameters. In this
* case, we'll need: the CA certificate ( given in the CACert field of
* the enrollment parameters ); the service point to be accessed
* ( given in the SSLUrl field of the enrollment parameters ); the
* lifetime of an SSL session ( given in the SSLLifetime field of the
* communications parameters ); and the communications manager itself.
*
* Input: a list of enrollment parameters ( for the CACert and SSLUrl fields of
* the OSPTENROLLPARAMS* ); a list of communications parameters
* ( for the SSLLifetime field of the OSPTCOMMPARAMS* ); and a
* reference to a communications manager.
*
* Output: the communications manager will have its parameters set, if
* possible. A return value of OSPC_ERR_NO_ERROR should indicate that
* there have been no problems. Any other return value will indicate
* an error.
*/
int OSPPInitSSLCommMgrParams(OSPTENROLLPARAMS *ospvEnrollParamsIn,
OSPTCOMMPARAMS *ospvCommParamsIn,
OSPTCOMM *ospvCommOut)
{
int retVal = OSPC_ERR_NO_ERROR;
OSPT_CERT caCert;
const OSPT_CERT *caCerts[1];
caCerts[0] = &caCert;
OSPM_DBGENTER(("ENTER: OSPPInitSSLCommMgrParams\n"));
/* Check the references to the parameters first. We'll be using
* the SSLUrl field of the enrollment parameters list for the
* service point, so we'll need to check that as well:
*/
if ((ospvEnrollParamsIn == OSPC_OSNULL) || (ospvEnrollParamsIn->SSLUrl == OSPC_OSNULL) ||
(ospvCommParamsIn == OSPC_OSNULL) || (ospvCommOut == OSPC_OSNULL))
{
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The parameters for initializing the enrollment server communications were invalid.\n");
}
/*
* If ( there were no problems ) then
* o set all of the communication manager's parameters, including
* connectivity parameters and the CA certificate.
* The CA certificate will be retrieved if necessary.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
/*
* Create a new security object. Note that we need the address
* of the communication's manager's security object pointer, so
* we need to dereference the ospvCommOut, access its security
* object, and then take its address. Not pretty.
*/
retVal = OSPPSecNew(&(ospvCommOut->Security));
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to create security object for comm mgr.");
}
}
/*
* If ( there weren't any problems ) then
* o set the SSL lifetime and max number of connections
* o record any errors.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPPSecSetSSLLifetime(ospvCommOut->Security, ospvCommParamsIn->SSLLifetime);
OSPM_DBGMISC(("CA cert: \n"));
OSPPDumpHex(ospvEnrollParamsIn->CACert, ospvEnrollParamsIn->CACertLen);
caCert.CertData = ospvEnrollParamsIn->CACert;
caCert.CertDataLength = ospvEnrollParamsIn->CACertLen;
retVal = OSPPSecSetAuthorityCertificates(ospvCommOut->Security, 1, caCerts);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to set the authority certs for the communications manager.\n");
}
}
/*
* Initialize the SSL context for the communication manager.
* If we fail, then report the error and set an error code.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPSSLWrapInit((void *)(ospvCommOut->Security));
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to initialize SSL context.\n");
}
}
OSPM_DBGMISC(("Return value: <%d>\n", retVal));
OSPM_DBGEXIT(("EXIT: OSPPInitSSLCommMgrParams\n"));
return retVal;
}
/*
* Initialize all of the non-SSL related parameters; we'll set the
* retry delay, http timeout, persistence values, and so on. All of
* the SSL-related parameters are set in the OSPPInitSSLCommMgrParams,
* which won't be necessary for certain functions ( like retrieving the
* CA certificate, which is currently done without SSL. )
*
* We'll be using this function for establishing basic parameters that
* aren't dependent on the use of the communications manager, so we'll
* need a generic service point specification, instead of assuming that
* it will be in the CAUrl or SSLUrl fields of an OSPTENROLLPARAM*
* structure. Doing the service point initialization here just eliminates
* duplication of effort.
*
* Input: pointers to the communications parameters and the service point's
* url, as well as the outgoing communications manager.
*
* Output: The communication manager's parameters should be set up.
* A return value of OSPC_ERR_NO_ERROR is returned if everything
* worked out; otherwise, an error code is returned.
*/
int OSPPInitNonSSLCommMgrParams(unsigned char *ospvServicePtUrlIn,
OSPTCOMMPARAMS *ospvCommParamsIn,
OSPTCOMM *ospvCommOut)
{
int retVal = OSPC_ERR_NO_ERROR;
OSPM_DBGENTER(("ENTER: OSPPInitNonSSLCommMgrParams\n"));
/* set an error code and complain if we can't use the input parameters: */
if ((ospvCommParamsIn == OSPC_OSNULL) || (ospvCommOut == OSPC_OSNULL)) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "At least one parameter is invalid (null)\n");
}
/*
* If ( there weren't any problems ) then
* o set the HTTP persistence
* o record any errors.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPCommSetPersistence(ospvCommOut, ospvCommParamsIn->HTTPPersistence);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to set HTTP persistence");
}
}
/*
* If ( there weren't any problems ) then
* o set the http retry delay
* o record any errors.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPCommSetRetryDelay(ospvCommOut, ospvCommParamsIn->HTTPRetryDelay);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to set HTTP retry delay.");
}
}
/*
* If ( there weren't any problems ) then
* o set the http retry limit
* o record any errors.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPCommSetRetryLimit(ospvCommOut, ospvCommParamsIn->HTTPRetryLimit);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to set HTTP Retry Limit.");
}
}
/*
* If ( there weren't any problems ) then
* o set the http max connections
* o record any errors.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPCommSetMaxConnections(ospvCommOut, ospvCommParamsIn->HTTPMaxConnections);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to set HTTP Max connections.");
}
}
/*
* If ( there weren't any problems ) then
* o set the http timeout
* o record any errors.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPCommSetTimeout(ospvCommOut, ospvCommParamsIn->HTTPTimeout);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to set HTTP timeout.");
}
retVal = OSPPCommSetConnSelectionTimeout(ospvCommOut, ospvCommParamsIn->HTTPTimeout);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to set Connection Selection timeout.");
}
}
/* Now set the service point and record any errors: */
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_DBGMISC(("enrollment url: <%s>\n", ospvServicePtUrlIn));
retVal = OSPPCommSetServicePoints(ospvCommOut, 1, (const char **)&(ospvServicePtUrlIn));
retVal = OSPPCommMgrSetSPMessageCount(ospvCommOut, NULL);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGMISC(("Unable to set service points: <%d>\n", retVal));
}
}
OSPM_DBGEXIT(("EXIT: OSPPInitNonSSLCommMgrParams\n"));
return retVal;
}
/*
* This function will: initialize a communications manager; construct
* a message to be sent to a service point; parse the results; and validate
* the contents of the certificate. We'll need the enrollment parameters
* so that we know which CA to contact for a certificate, and we'll
* need the communications parameters for initializing the communications
* manager. The enrollment parameters will also be used to store the
* CA certificate that is returned ( accessed by
* ospvEnrollParamsInOut->CACert ).
*
* Input: a pointer to the enrollment parameter list and a pointer to the
* communications parameter list.
*
* Output: the CA certificate ( if it was found ) in the enrollment parameter
* list ( under the CACert field ). OSPC_ERR_NO_ERROR is returned
* if everything went ok; otherwise, some other error code is returned.
*/
int OSPPRetrieveCACert(OSPTENROLLPARAMS *ospvEnrollParamsInOut,
OSPTCOMMPARAMS *ospvCommParamsIn)
{
int retVal = OSPC_ERR_NO_ERROR;
/* The structure used for encapsulating the request and response: */
OSPT_MSG_INFO *certReqMsg = OSPC_OSNULL;
/*
* The request that we'll be building and sending to the CA via the
* certReqMsg ( which will also hold the response. )
*/
unsigned char *caRequest = OSPC_OSNULL;
/*
* The communications manager used for contacting the enrollment server
* ( or its CA ) and requesting the CA certificate:
*/
OSPTCOMM *caCommMgr = OSPC_OSNULL;
/* The CA certificate response that will be null-terminated: */
unsigned char *caCertResponse = OSPC_OSNULL;
OSPM_DBGENTER(("ENTER: OSPPRetrieveCACert\n"));
/* Check the input parameters for null values first: */
if ((ospvCommParamsIn == OSPC_OSNULL) || (ospvEnrollParamsInOut == OSPC_OSNULL)) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "Parameters were invalid; at least one was null.\n");
}
/* Now initialize the communications manager: */
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPInitNonSecureCommMgr(ospvEnrollParamsInOut, ospvCommParamsIn, &caCommMgr);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to init communication with the CA.\n");
}
}
/*
* If ( the parameters were ok ) then
* o initialize the memory for the outbound message.
* o if ( we coldn't initialize it ) then
* - set an error code and complain.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPMsgInfoNew(&certReqMsg);
OSPM_MALLOC(certReqMsg->ContentType, unsigned char, OSPM_STRLEN(OSPC_COMM_TEXT_MSG) + 1);
if (certReqMsg->ContentType == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "No memory is available for the CA certificate request.\n");
}
}
/*
* If ( we could create the message info structure ) then
* o create the retrieval request to be sent
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPCreateCARetrievalRequest(ospvEnrollParamsInOut, &caRequest);
/* Print out an error if there was something wrong: */
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to create CA retrieval request.");
}
}
/*
* If ( the request could be created ) then
* o set the request message and its size for the MessageInfo:
* o add the MessageInfo to the queue; the request should be
* transmitted to the enrollment server and a request received.
* o if ( sending the request failed ) then write an error message.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
certReqMsg->RequestMsg = caRequest;
certReqMsg->RequestSz = OSPM_STRLEN((const char *)caRequest);
OSPM_STRCPY((char *)(certReqMsg->ContentType), OSPC_COMM_TEXT_MSG);
OSPM_DBGMISC(("request msg: <%s>, <%d>\n", certReqMsg->RequestMsg, certReqMsg->RequestSz));
retVal = OSPPCommAddTransaction(caCommMgr, certReqMsg);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to retrieve CA certificate.");
}
}
/*
* If ( sending the request was successful ) then
* o Get the CA certificate out of the response.
* o if ( there were problems getting it out ) then
* - print an error.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
if (certReqMsg->ResponseMsg == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_INVALID_RESPONSE;
OSPM_DBGERRORLOG(retVal, "The response received for the CA certificate was empty.\n");
}
}
/*
* If ( the return value was ok ) then
* o check the error code returned as well; it's possible that the
* error code from the enrollment server ( at the HTTP level; this
* is not equivalent to the status of the enrollment request )
* didn't result in a bad return value. In this case, report an
* error.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
if (certReqMsg->ErrorCode != OSPC_ERR_NO_ERROR) {
retVal = OSPC_ERR_ENROLL_INVALID_RESPONSE;
OSPM_DBGERRORLOG(retVal, "The error code received invalidates the CA's response.\n");
OSPM_DBGMISC(("Error code received from server: <%d>\n", certReqMsg->ErrorCode));
}
}
/*
* Copy the response into something that's null-terminated; that way,
* we won't have to worry about overwriting or reading other memory:
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MALLOC(caCertResponse, unsigned char, certReqMsg->ResponseSz + 1);
if (caCertResponse == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "No memory for the null-terminated response.\n");
}
}
/*
* Everything looks alright with the response so far, so now let's get
* the CA certificate ( base64 decoded ) from the response:
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MEMSET(caCertResponse, 0, certReqMsg->ResponseSz + 1);
OSPM_STRNCPY(caCertResponse, certReqMsg->ResponseMsg, certReqMsg->ResponseSz);
retVal = OSPPExtractCACertFromResponse(caCertResponse, certReqMsg->ResponseSz, &(ospvEnrollParamsInOut->CACert),
&(ospvEnrollParamsInOut->CACertLen), &(ospvEnrollParamsInOut->CACertB64), &(ospvEnrollParamsInOut-> CACertB64Len));
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to extract CA certificate from response.");
}
}
/*
* If we got the binary string for the CA certificate successfully,
* then we'll have to validate it. Here we'll turn it into an ASN.1
* object, check the structure, check the signature ( the CA certificate
* should be self-signed ), and check the fingerprint. The enrollment
* parameters structure should contain the CA certificate and the acceptable
* fingerprint for the certificate prior to the validation stage.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPValidateCACertificate(ospvEnrollParamsInOut);
}
/* Now it's time to shutdown the communications manager: */
if (caCommMgr != OSPC_OSNULL) {
OSPM_DBGMISC(("Cleaning up communications manager...\n"));
OSPPEnrollCleanupCommMgr(&caCommMgr);
}
/* Destroy the memory for the enrollment request: */
OSPPMsgInfoDelete(&certReqMsg);
/* Destroy the null-terminated CA certificate response if necessary: */
if (caCertResponse != OSPC_OSNULL) {
OSPM_FREE(caCertResponse);
}
OSPM_DBGEXIT(("EXIT: OSPPRetrieveCACert\n"));
return retVal;
}
/*
* Create the CA retrieval request. This function should create that
* request and put it into the ospvCARequest that gets passed in. Note
* that the memory alloced here for ospvCARequest will not be unmalloced
* by this function; it will have to be freed by the calling function.
*
* Input: ospvCARequest ( also written to; should be empty initially. )
*
*/
int OSPPCreateCARetrievalRequest(OSPTENROLLPARAMS *ospvEnrollParamsIn,
unsigned char **ospvCARequestOut)
{
int retVal = OSPC_ERR_NO_ERROR;
/* Length of the request being built: */
int requestStrLen = -1;
/* The request being built: */
unsigned char *requestStr = OSPC_OSNULL;
OSPM_DBGENTER(("ENTER: OSPPCreateCARetrievalRequest\n"));
/* If ( the output request is null ) then set an error code */
if (ospvCARequestOut == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
}
if (retVal == OSPC_ERR_NO_ERROR)
/*
* If ( everything has gone ok so far ) then
* o calculate the length of the request: the length of
* "operation=GetCACert".
* o allocate that much memory, plus one byte ( for null )
* o if ( we couldn't malloc memory ) then
* o something really bad happened, so set the return value to
* an error code and get out.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
requestStrLen = OSPM_STRLEN(OSPC_ENROLL_OPERATION_REQ_PARAM) +
OSPM_STRLEN(OSPC_ENROLL_NAME_VALUE_DELIMITER) +
OSPM_STRLEN(OSPC_ENROLL_OP_CA_CERT_REQ_PARAM);
OSPM_MALLOC(requestStr, unsigned char, requestStrLen + 1);
if (requestStr == OSPC_OSNULL) {
OSPM_DBGERRORLOG(retVal, "Unable to allocate space for request\n");
}
}
/*
* If ( the parameters and the memory setting were ok ) then
* o copy the request parameters into the request
* o set the CA certificate request to be the string that gets built.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MEMSET(requestStr, 0, requestStrLen + 1);
OSPM_SPRINTF((char *)requestStr, "%s%s%s", OSPC_ENROLL_OPERATION_REQ_PARAM, OSPC_ENROLL_NAME_VALUE_DELIMITER, OSPC_ENROLL_OP_CA_CERT_REQ_PARAM);
*ospvCARequestOut = requestStr;
OSPM_DBGMISC(("request string: <%s>\n", requestStr));
}
OSPM_DBGEXIT(("EXIT: OSPPCreateCARetrievalRequest\n"));
return retVal;
}
/*
* Extract the CA certificate from the response and base64-decode it.
* We'll also use the base64-encoded certificate to be passed back to
* the user so that they can use it again on input ( instead of having
* to redo the base64 encoding. )
*
* Input: a character string representing the response to be scanned,
* along with outgoing parameters for the binary BER-encoding
* of the CA certificate, its length, the base64 encoding of the
* certificate, and its length as well.
*
* Output: Along with the values of the outgoing parameters, a return value
* of OSPC_ERR_NO_ERROR is returned if the variables could be
* allocated and assigned properly. Otherwise, a return value of
* something other than OSPC_ERR_NO_ERROR is returned.
*/
int OSPPExtractCACertFromResponse(unsigned char *ospvResponseIn,
unsigned ospvResponseLenIn,
unsigned char **ospvCACertOut,
unsigned *ospvCACertLenOut,
unsigned char **ospvCACertB64Out,
unsigned *ospvCACertB64LenOut)
{
int retVal = OSPC_ERR_NO_ERROR;
int caCertB64Len = 0;
unsigned char *caCertB64 = OSPC_OSNULL;
OSPM_DBGENTER(("ENTER: OSPPExtractCACertFromResponse\n"));
/* Check the input parameters first: */
if ((ospvResponseIn == OSPC_OSNULL) || (ospvCACertOut == OSPC_OSNULL) || (ospvCACertLenOut == OSPC_OSNULL) ||
(ospvCACertB64Out == OSPC_OSNULL) || (ospvCACertB64LenOut == OSPC_OSNULL))
{
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The arguments for extracting a CA certificate are invalid.\n");
}
/*
* Retrieve the base64-encoded CA certificate from the response;
* the memory should be allocated for the caCertB64 inside of
* OSPPExtractFieldFromResponse.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPExtractFieldFromResponse(ospvResponseIn, ospvResponseLenIn, (unsigned char *)OSPC_ENROLL_CA_CERT_RSP_PARAM, &caCertB64);
/* Complain if we couldn't find the CA certificate: */
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to find the base64-encoded CA certificate in the response.\n");
}
/* Set an error code and complain if the return value was null: */
else if (caCertB64 == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "The base64-encoded CA certificate returned was null.\n");
}
}
/*
* If ( we could find the CA certificate ) then
* o get its length
* o set an error code and complain if it's empty
*/
if (retVal == OSPC_ERR_NO_ERROR) {
caCertB64Len = OSPM_STRLEN((char *)caCertB64);
if (caCertB64Len <= 0) {
OSPM_DBGERRORLOG(retVal, "The CA certificate returned was empty.\n");
}
}
/*
* IF ( it looks like the CA certificate might be ok ) then
* o allocate memory for the BER-encoded CA certificate ( that is, the
* one that's been base64-decoded ); we'll use the pointer returned
* to caCertB64 for the outgoing base64-encoding of the cert, so we
* don't need any space for it here
* o complain if the space couldn't be allocated.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MALLOC(*ospvCACertOut, unsigned char, 2 * caCertB64Len + 1);
if (*ospvCACertOut == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "Unable to allocate memory for the certificate buffers.\n");
}
}
/*
* If ( the memory could be allocated ) then
* o initialize it
* o set the maximum size of the base64-decoded cert to be twice the
* length of the base64-encoded cert. This isn't a very tight
* space allocation ( in fact, the decoding of a base64-encoded message
* is 4 * ceil( caCertB64Len/3 ) ), but it's required for the
* base64 decoding mechanism.
* o complain if we couldn't get it
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MEMSET(*ospvCACertOut, 0, 2 * caCertB64Len + 1);
*ospvCACertLenOut = 2 * caCertB64Len;
retVal = OSPPBase64Decode((char *)caCertB64, caCertB64Len, *ospvCACertOut, ospvCACertLenOut);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Bad base 64 encoding for CA certificate\n");
}
}
/*
* If ( we could successfully base64-decode the certificate ) then
* o copy the base64-encoded CA certificate and set its length.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
*ospvCACertB64Out = caCertB64;
*ospvCACertB64LenOut = caCertB64Len;
}
OSPM_DBGEXIT(("EXIT: OSPPExtractCACertFromResponse\n"));
return retVal;
}
/*
* Now take the enrollment parameter's CA certificate fingerprint in hex
* ( which should have been taken from a secure channel, such as paper
* [ if ubiquity can be considered security ] or an SSL session with the
* enrollment server's accompanying web site ( if available. ) If the
* fingerprint is missing, then an error will not be generated; we'll assume
* for now ( although this is debatable ) that the fingerprint isn't
* necessary. If any of the other parameters are otherwise null, then
* this function will fail. If the CA certificate is missing, then this
* function will fail regardless of whether or not we care about checking
* for the fingerprint. This may be changed too ( just rearrange the ordering
* of the statements for checking the null values. )
*
* Input: a pointer to the enrollment parameters, which contains the CA
* certificate and the CA's intended fingerprint.
*
* Output: an error code if anything is null or if the fingerprint cannot be
* taken or doesn't match up to what's expected.
*/
int OSPPValidateCACertificate(OSPTENROLLPARAMS *ospvEnrollParams)
{
int retVal = OSPC_ERR_NO_ERROR;
unsigned char *caFprint = OSPC_OSNULL;
OSPTASN1OBJECT *caCertASN1Object = OSPC_OSNULL;
int caFprintLen = -1;
/* The binary version of the input fingerprint: */
unsigned char *inputFprintBin = OSPC_OSNULL;
int inputFprintBinLen = 0;
/*
* This is the index of the CA certificate's parent ( itself ) within the
* given list. It's ignored because it should be self-signed.
*/
int ignoreIndex = -1;
OSPM_DBGENTER(("ENTER: OSPPValidateCACertificate\n"));
/* If ( the input parameters are bad ) then
* o there's nothing we can do; set the errorcode and complain.
*/
if (ospvEnrollParams == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "Invalid enrollment parameters passed in.\n");
}
/*
* Now check the CA certificate's value; if the CA certificate is null
* or empty, then we can't check it. In this case, set an errorcode
* and complain.
*/
if ((ospvEnrollParams->CACert == OSPC_OSNULL) ||
(ospvEnrollParams->CACertLen <= 0)) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The CA certificate being validated is empty.\n");
}
/* Create an ASN1 object out of the CA certificate received. If we cannot
* form a certificate, then we know that there's something wrong with the
* general format of the certificate.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPX509CertCreate(ospvEnrollParams->CACert, &caCertASN1Object);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "The CA certificate received is not a valid X.509 cert.\n");
}
}
/*
* Then we successfully parsed the CA certificate's structure; now let's
* check the signature. The signature must be self-signed; if it isn't,
* then we'll need some other way of authenticating the certificate
* ( such as assuming that the CA certificate entered by hand is valid.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_DBGMISC(("CA cert:\n"));
OSPPDumpHex(caCertASN1Object->ElementInfo->Content, caCertASN1Object->ElementInfo->ContentLength);
retVal = OSPPX509CertValidateCertificate(caCertASN1Object, &caCertASN1Object, 1, &ignoreIndex);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "The CA certificate chain is not self-signed.\n");
}
}
/*
* If the fingerprint passed in was null, then we're done; we don't
* care about the CA fingerprint. The security policy here may be
* changed if we absolutely require the CA's fingerprint. We won't
* return right away if there's no other processing to be done,
* simply for the sake of having a single entry/exit point.
*/
if ((ospvEnrollParams->CAFprint != OSPC_OSNULL) &&
(OSPM_STRLEN((char *)(ospvEnrollParams->CAFprint)) > 0)) {
OSPM_DBGMISC(("fingerprint on input: \n"));
OSPPDumpHex(ospvEnrollParams->CAFprint, 40);
if (ospvEnrollParams->CACert == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The CA certificate is missing.\n");
}
/* Create the memory for the hash: */
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MALLOC(caFprint, unsigned char, OSPC_ENROLL_MAX_FPRINT_SIZE + 1);
OSPM_MALLOC(inputFprintBin, unsigned char, 2 * OSPC_ENROLL_MAX_FPRINT_SIZE + 1);
/*
* If ( the memory allocation didn't work ) then
* o set an error code and complain; we'll clean up any
* memory allocated at the end of this block anyway.
*/
if ((caFprint == OSPC_OSNULL) || (inputFprintBin == OSPC_OSNULL)) {
retVal = OSPC_ERR_ENROLL_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "Unable to create memory for the fingerprint.\n");
}
}
/*
* Now turn the hexadecimal ASCII into binary; this is better than
* comparing two hex encodings that may have different capitalization
* schemes.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
inputFprintBinLen = 2 * OSPC_ENROLL_MAX_FPRINT_SIZE;
retVal = OSPPHexToBinary(ospvEnrollParams->CAFprint, OSPM_STRLEN((char *)(ospvEnrollParams-> CAFprint)), inputFprintBin,
(unsigned *)(&inputFprintBinLen));
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "The fingerprint passed in could not be decoded to binary.\n");
OSPM_DBGMISC(("fingerprint passed in: <%s>\n", ospvEnrollParams->CAFprint));
}
}
/*
* If ( we could initialize for the hash ) then
* o initialize the memory;
* o take the hash;
* o check the return value for calculating the fingerprint.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MEMSET(caFprint, 0, OSPC_ENROLL_MAX_FPRINT_SIZE + 1);
OSPPDumpHex(caCertASN1Object->ElementInfo->Content, caCertASN1Object->ElementInfo->ContentLength);
/*
* Use the CA certificate and its length as the parameters for
* the fingerprint/digest; put the digest in caFprint and its
* length in caFprintLen. We'll use SHA 1 for the digesting
* algorithm; the other two paramters( OSPC_OSNULL and 0 ) are
* superfluous values; ignore them and their green curtain.
*/
retVal = OSPPCryptoWrapDigest(caFprint, (unsigned *)(&caFprintLen), OSPC_OSNULL, 0, ospvEnrollParams->CACert,
ospvEnrollParams->CACertLen, OSPC_CRYPTO_FLAG_USE_SHA1_DIGEST);
OSPM_DBGMISC(("retVal for digesting: <%d>\n", retVal));
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_DBGMISC(("CA fingerprint:\n"));
OSPPDumpHex(caFprint, caFprintLen);
}
}
/*
* Now check the fingerprint against what we were given. Translate
* the fingerprint that was taken into hex and compare it against the
* hex fingerprint given on input.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_DBGMISC(("input fingerprint: \n"));
OSPPDumpHex(inputFprintBin, caFprintLen);
if (caFprintLen != inputFprintBinLen) {
retVal = OSPC_ERR_ENROLL_BAD_FPRINT;
} else if (OSPM_MEMCMP(inputFprintBin, caFprint, caFprintLen) != 0) {
retVal = OSPC_ERR_ENROLL_BAD_FPRINT;
}
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_DBGMISC(("The CA fingerprint matches the one passed in.\n"));
} else {
OSPM_DBGERRORLOG(retVal, "The CA certificate received had a bad fingerprint.\n");
}
}
/* Free up everything that we've allocated, but only if the
* space exists:
*/
if (caFprint != OSPC_OSNULL) {
OSPM_FREE(caFprint);
}
if (inputFprintBin != OSPC_OSNULL) {
OSPM_FREE(inputFprintBin);
}
}
/* This object is allocated outside the scope of when we check
* the CA certificate's fingerpring, so save the freeing of this
* object until the end.
*/
if (caCertASN1Object != OSPC_OSNULL) {
OSPPASN1ObjectDelete(&caCertASN1Object);
}
OSPM_DBGEXIT(("EXIT: OSPPValidateCACertificate\n"));
return retVal;
}
/*
* Translate the given hex string into binary. We'll be given the
* length of the hex string and the length of the binary string as
* well. We'll expect that the binary string already has enough
* memory allocated ( at least twice as much as the hex encoding. )
*
* The length of the hex string dictates how much memory will be copied.
* For example, if the length of the hex string is 200 bytes ( or 100 bytes
* in its full binary representation ), then the number of octets to
* be copied from the hex string can be anywhere from 2 to 200.
*
* The length of the binary string initially refers to the amount of
* space that the binary string can contain. It will be set to the
* number of bytes that were copied into the binary string.
*
* Input: the hex string, the length of the hex string, the binary
* representation, and the length of the binary representation
*
* Output: the binary representation and its length will be output.
* A return code of OSPC_ERR_NO_ERRRO ( 0 ) will be returned
* if everything went alright; otherwise, a non-zero code
* will be returned.
*/
int OSPPHexToBinary(unsigned char *ospvHexStr,
unsigned ospvHexStrLen,
unsigned char *ospvBinaryStr,
unsigned *ospvBinaryStrLen)
{
int retVal = OSPC_ERR_NO_ERROR;
/* Index for looping through the hex string contents: */
unsigned hexStrIndex = 0;
/* The next two bytes from the hex string that will compose the next byte in the binary string: */
unsigned char *nextByte = OSPC_OSNULL;
/* The next word of data to be placed in the binary string; this will be the output of a strtol on nextByte: */
long nextWord = 0;
/* If ( any of the values input are null ) then complain and set an error code. */
if ((ospvHexStr == OSPC_OSNULL) ||
(ospvBinaryStr == OSPC_OSNULL) || (ospvBinaryStrLen == OSPC_OSNULL)) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "A null pointer was passed in.\n");
}
/*
* If ( the hex string is not as long as what the caller wants
* to copy from it ) then
* o set an error code and complain.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
if (OSPM_STRLEN((char *)ospvHexStr) < (size_t)ospvHexStrLen) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The requested length of the hex string to be translated is longer than the string itself.\n");
}
}
/*
* If ( the caller wants more bytes from the binary string than are
* allocated to it or if the binary string is empty ) then
* o set an error code and complain.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
if ((*ospvBinaryStrLen <= 0) ||
(*ospvBinaryStrLen < 2 * ospvHexStrLen)) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The given binary string is too small.\n");
OSPM_DBGMISC(("%d < 2 * %d\n", *ospvBinaryStrLen, ospvHexStrLen));
}
}
/*
* For ( each character )
* o if ( the character isn't a hex digit ) then
* - set an error code and return.
*/
for (hexStrIndex = 0; hexStrIndex < ospvHexStrLen; hexStrIndex++) {
if (!OSPM_ISXDIGIT(ospvHexStr[hexStrIndex])) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The hex string on input is not entirely hex characters.\n");
OSPM_DBGMISC(("character %c at offset %d of %s is not a hex character\n", ospvHexStr[hexStrIndex], hexStrIndex, ospvHexStr));
}
}
/*
* Try to allocate memory for the chunk of data that will be used for
* translating the hex to binary. Set an error code and complain
* if we can't.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MALLOC(nextByte, unsigned char, 3);
if (nextByte == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "Unable to allocate memory for translating hex ascii strings to binary.\n");
}
}
/*
* If ( all of the parameters are ok ) then
* o reset the length of the binary output string.
* o initialize the memory for the binary string.
* o for ( every octet in the hex string that we want to copy ) do
* - copy the next octet into some other space
* - turn it into a long int.
* - take the last 8 bits ( wherever they may be ) and put them
* at the end of the binary string; increment the length of the
* binary string by one.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
*ospvBinaryStrLen = 0;
OSPM_MEMSET(nextByte, 0, 3);
for (hexStrIndex = 0; (hexStrIndex < ospvHexStrLen); hexStrIndex += 2) {
OSPM_SPRINTF((char *)nextByte, "%.2s", ospvHexStr + hexStrIndex);
nextWord = OSPM_STRTOL((char *)nextByte, NULL, 16);
OSPM_DBGMISC(("nextWord: %ld, %d\n", nextWord, (nextWord && OSPC_LONG_TO_BYTE_MASK)));
ospvBinaryStr[(*ospvBinaryStrLen)++] = (unsigned char)(nextWord & OSPC_LONG_TO_BYTE_MASK);
}
OSPM_DBGMISC(("final binary encoding:\n"));
OSPPDumpHex(ospvBinaryStr, *ospvBinaryStrLen);
}
/* Free up any memory we allocated: */
if (nextByte != OSPC_OSNULL) {
OSPM_FREE(nextByte);
}
return retVal;
}
/*
* Given the response to scan and the field to search for, extract the
* contents of that field into the outgoing value. We'll be careful
* not to accidentally use names that look similar but which have different
* lengths. For example, if we're looking for the field "def" and we're
* given "abcdef=ghi&def=jkl", then we want to return "jkl" and not
* "ghi". If we find an appropriate field, then we'll save it in
* the outgoing pointer ( which we'll also allocate. )
*
* Input: the response to be scanned, the field to look for, and a pointer
* to a string that will contain the field's value ( if we find it. )
*
* Output: *ospvValueOut will be non-null and will contain the contents of
* the field if the field can be found and is non-empty. Otherwise,
* if the field is empty or can't be found, then an error code
* other than OSPC_ERR_NO_ERROR will be returned and *ospvValueOut
* will be untouched.
*/
int OSPPExtractFieldFromResponse(unsigned char *ospvResponse,
unsigned ospvResponseLen,
unsigned char *ospvSearchField,
unsigned char **ospvValueOut)
{
int retVal = OSPC_ERR_NO_ERROR;
/* This will point to the value that we find, if we find it: */
unsigned char *beginValuePtr = OSPC_OSNULL;
/* This points to the name that we're trying to match on: */
unsigned char *nextNamePtr = OSPC_OSNULL;
/* Flag for determining whether or not we found a value: */
OSPTBOOL valueFound = OSPC_FALSE;
OSPM_DBGENTER(("ENTER: OSPPExtractFieldFromResponse\n"));
/*
* Check for any null or empty parameters passed in first.
* We'll be allocating *ospvValueOut, so don't check its contents
* ( just check that ospvValueOut isn't null. )
*/
if ((ospvResponse == OSPC_OSNULL) || (ospvResponseLen <= 0) || (ospvSearchField == OSPC_OSNULL) ||
(ospvValueOut == OSPC_OSNULL) || (OSPM_STRLEN((char *)ospvSearchField) <= 0))
{
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "Invalid arguments for searching for a field\n");
}
/*
* We know that the parameters are valid, so allocate enough memory
* to store the value that we find. The maximum possible size is
* OSPM_STRLEN( ospvResponse ) - 2, which would happen if the response
* was a one-field value with a one-character name ( such as
* "a=1073741824" .) So, go ahead and allocate the size of the string.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MALLOC(beginValuePtr, unsigned char, ospvResponseLen);
if (beginValuePtr == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "Unable to allocate memory for saving the field's value.\n");
}
}
/*
* If ( we could allocate the memory ) then
* o get the beginning of the string
* o do:
* - find the first occurrence of a name in the string.
* - if ( the occurrence is null ) then
* o we're done; we couldn't find a name-value pair for the
* given name.
* - otherwise:
* o check the name to see if it matches a name-value pair
* ( that is, we don't want to use "abcd=efgh" if we're looking
* for the name "bc" )
* o if ( we matched on one string ) then we must have found
* something for a name and a value.
* - if ( the value is null ) then
* o the value we found here is empty; we can't use it.
* - else if ( the name was at the beginning of the response )
* OR ( the previous character is the field delimiter )
* o then we know that we've actually found the name
* and hence the correct value. We know that we
* haven't matched on "abcd=efgh" if we're looking
* for the name "bc", since we compare the name we
* found to the beginning of the string. Likewise,
* cases like "abcd=efgh&ijkl=mnop" will fall through
* the cracks if we're looking for "jk" ( since
* 'i' != '&' )
* - if ( we didn't find anything on this iteration ) then
* o increment the pointer so that we don't get the same case.
* while ( we haven't found anything ) and
* ( we haven't run into any problems )
*/
if (retVal == OSPC_ERR_NO_ERROR) {
nextNamePtr = ospvResponse;
do {
nextNamePtr = (unsigned char *)OSPM_STRSTR((char *)nextNamePtr, (char *)ospvSearchField);
if (nextNamePtr == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_SEARCH_FIELD_NOT_FOUND;
}
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_DBGMISC(("nextNamePtr: <%s>\n", nextNamePtr));
if (OSPM_SSCANF(nextNamePtr, OSPC_ENROLL_SEARCH_PATTERN, beginValuePtr) > 0) {
if (beginValuePtr == OSPC_OSNULL) {
/* Do nothing; the field value was empty. */
OSPM_DBGMISC(("The value for this field is empty; ignonring current value.\n"));
} else if ((nextNamePtr == ospvResponse) || (OSPM_STRCHR (OSPC_ENROLL_URL_FIELD_DELIMITERS, *(nextNamePtr - 1)))) {
valueFound = OSPC_TRUE;
} else {
OSPM_DBGMISC(("False hit.\n"));
}
} else {
OSPM_DBGMISC(("The given attribute was a false hit.\n"));
}
}
/* Make sure that we don't get the same case again: */
if (valueFound != OSPC_TRUE) {
nextNamePtr++;
}
} while ((valueFound == OSPC_FALSE) && (retVal == OSPC_ERR_NO_ERROR));
}
if ((valueFound != OSPC_TRUE) || (beginValuePtr == OSPC_OSNULL)) {
retVal = OSPC_ERR_ENROLL_SEARCH_FIELD_NOT_FOUND;
OSPM_DBGERRORLOG(retVal, "Unable to find the field requested.\n");
OSPM_DBGMISC(("Unable to find field <%s> in <%s>\n", ospvSearchField, ospvResponse));
}
/* Copy the contents of the string found into the outgoing string if we found something we can use: */
if (retVal == OSPC_ERR_NO_ERROR) {
retVal = OSPPCopyString(ospvValueOut, beginValuePtr);
if (retVal != OSPC_ERR_NO_ERROR) {
OSPM_DBGERRORLOG(retVal, "Unable to copy value found into the outgoing pointer.\n");
}
}
/* Now free up the pointer we found, regardless of whether or not we were successful: */
if (beginValuePtr != OSPC_OSNULL) {
OSPM_FREE(beginValuePtr);
}
OSPM_DBGEXIT(("EXIT: OSPPExtractFieldFromResponse\n"));
return retVal;
}
/*
* copy the source string to the destination string; allocate and initialize
* enough space in the destination string that we can fit everything in
* the source string.
*
* Input: pointer to the destination string and the source string to be
* copied.
*
* Output: *ospvDestStr should be a replica of ospvSrcStr if everything goes
* well; in this case, OSPC_ERR_NO_ERROR is returned. Otherwise,
* an error code other than OSPC_ERR_NO_ERROR is returned.
*/
int OSPPCopyString(unsigned char **ospvDestStr, unsigned char *ospvSrcStr)
{
int retVal = OSPC_ERR_NO_ERROR;
/*
* Don't assign the source string to the destination string
* until the end; we'll perform all of our operations on this
* string instead:
*/
unsigned char *tmpDestStr = OSPC_OSNULL;
/* This is the length of the source string: */
int srcStrLen = 0;
OSPM_DBGENTER(("ENTER OSPPCopyString\n"));
/* Check for valid inputs first: */
if ((ospvDestStr == OSPC_OSNULL) || (ospvSrcStr == OSPC_OSNULL)) {
retVal = OSPC_ERR_ENROLL_INVALID_ARG;
OSPM_DBGERRORLOG(retVal, "The parameters for copying a string were invalid.\n");
}
/*
* if ( the parameters look ok ) then
* o get the length of the source string
* o if ( the source is empty ) then
* - set an error code and complain.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
srcStrLen = OSPM_STRLEN((char *)ospvSrcStr);
if (srcStrLen <= 0) {
retVal = OSPC_ERR_ENROLL_SOURCE_STRING_EMPTY;
OSPM_DBGERRORLOG(retVal, "Unable to copy empty source string.\n");
}
}
/*
* If ( the source string is ok ) then
* o allocate enough memory for the output string
* o if ( we couldn't do it ) then
* - complain
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MALLOC(tmpDestStr, unsigned char, srcStrLen + 1);
if (tmpDestStr == OSPC_OSNULL) {
retVal = OSPC_ERR_ENROLL_NO_MEMORY;
OSPM_DBGERRORLOG(retVal, "Unable to allocate memory for destination string.\n");
}
}
/*
* If ( we could allocate the memory ) then
* o initialize the memory
* o copy the strings
* o assign the string created to the outgoing pointer.
*/
if (retVal == OSPC_ERR_NO_ERROR) {
OSPM_MEMSET(tmpDestStr, 0, srcStrLen + 1);
OSPM_STRCPY((char *)tmpDestStr, (char *)ospvSrcStr);
*ospvDestStr = tmpDestStr;
}
/* Else we had some problem so
* o free up any memory we may have allocated:
*/
else {
if (tmpDestStr != OSPC_OSNULL) {
OSPM_FREE(tmpDestStr);
}
}
OSPM_DBGEXIT(("EXIT OSPPCopyString\n"));
return retVal;
}
|