Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

377 lines
13 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: selfsign.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "global.hxx"
  11. #include <dbgdef.h>
  12. PCCERT_CONTEXT
  13. WINAPI
  14. CertCreateSelfSignCertificate(
  15. IN HCRYPTPROV hProv,
  16. IN PCERT_NAME_BLOB pSubjectIssuerBlob,
  17. IN DWORD dwFlags,
  18. OPTIONAL PCRYPT_KEY_PROV_INFO pKeyProvInfo,
  19. OPTIONAL PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
  20. OPTIONAL PSYSTEMTIME pStartTime,
  21. OPTIONAL PSYSTEMTIME pEndTime,
  22. OPTIONAL PCERT_EXTENSIONS pExtensions
  23. ) {
  24. PCCERT_CONTEXT pCertContext = NULL;
  25. DWORD errBefore = GetLastError();
  26. DWORD err = ERROR_SUCCESS;
  27. DWORD cbPubKeyInfo = 0;
  28. PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL;
  29. BYTE * pbCert = NULL;
  30. DWORD cbCert = 0;
  31. LPSTR sz = NULL;
  32. DWORD cb = 0;
  33. BYTE * pbToBeSigned = NULL;
  34. BYTE * pbSignature = NULL;
  35. CERT_INFO certInfo;
  36. GUID serialNbr;
  37. CRYPT_KEY_PROV_INFO keyProvInfo;
  38. CERT_SIGNED_CONTENT_INFO sigInfo;
  39. CRYPT_ALGORITHM_IDENTIFIER algID;
  40. LPWSTR wsz = NULL;
  41. BOOL fFreehProv = FALSE;
  42. HCRYPTKEY hKey = NULL;
  43. UUID guidContainerName;
  44. RPC_STATUS RpcStatus;
  45. memset(&certInfo, 0, sizeof(CERT_INFO));
  46. memset(&serialNbr, 0, sizeof(serialNbr));
  47. memset(&keyProvInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
  48. memset(&sigInfo, 0, sizeof(CERT_SIGNED_CONTENT_INFO));
  49. // do key spec now because we need it
  50. if(pKeyProvInfo == NULL)
  51. keyProvInfo.dwKeySpec = AT_SIGNATURE;
  52. else
  53. keyProvInfo.dwKeySpec = pKeyProvInfo->dwKeySpec;
  54. // see if we have an hProv, if not, create one
  55. if(hProv == NULL) {
  56. fFreehProv = TRUE;
  57. // if not prov info, make one up, signing RSA cert, default provider
  58. if(pKeyProvInfo == NULL) {
  59. RpcStatus = UuidCreate(&guidContainerName);
  60. if (!(RPC_S_OK == RpcStatus ||
  61. RPC_S_UUID_LOCAL_ONLY == RpcStatus)) {
  62. // Use stack randomness
  63. ;
  64. }
  65. // note: unlike UUidToString, always must LocalFree() returned memory
  66. UuidToStringU(&guidContainerName, &wsz);
  67. if( !CryptAcquireContextU(
  68. &hProv,
  69. wsz,
  70. NULL,
  71. PROV_RSA_FULL,
  72. CRYPT_NEWKEYSET) ) {
  73. hProv = NULL;
  74. goto ErrorCryptAcquireContext;
  75. }
  76. }
  77. else {
  78. // first use the existing keyset
  79. if( !CryptAcquireContextU(
  80. &hProv,
  81. pKeyProvInfo->pwszContainerName,
  82. pKeyProvInfo->pwszProvName,
  83. pKeyProvInfo->dwProvType,
  84. pKeyProvInfo->dwFlags) ) {
  85. // otherwise generate a keyset
  86. if( !CryptAcquireContextU(
  87. &hProv,
  88. pKeyProvInfo->pwszContainerName,
  89. pKeyProvInfo->pwszProvName,
  90. pKeyProvInfo->dwProvType,
  91. pKeyProvInfo->dwFlags | CRYPT_NEWKEYSET) ) {
  92. hProv = NULL;
  93. goto ErrorCryptAcquireContext;
  94. }
  95. }
  96. }
  97. // we have the keyset, now make sure we have the key gen'ed
  98. if( !CryptGetUserKey( hProv,
  99. keyProvInfo.dwKeySpec,
  100. &hKey) ) {
  101. // doesn't exist so gen it
  102. assert(hKey == NULL);
  103. if(!CryptGenKey( hProv,
  104. keyProvInfo.dwKeySpec,
  105. 0,
  106. &hKey) ) {
  107. goto ErrorCryptGenKey;
  108. }
  109. }
  110. }
  111. // get the exportable public key bits
  112. if( !CryptExportPublicKeyInfo( hProv,
  113. keyProvInfo.dwKeySpec,
  114. X509_ASN_ENCODING,
  115. NULL,
  116. &cbPubKeyInfo) ||
  117. (pPubKeyInfo =
  118. (PCERT_PUBLIC_KEY_INFO) PkiNonzeroAlloc(cbPubKeyInfo)) == NULL ||
  119. !CryptExportPublicKeyInfo( hProv,
  120. keyProvInfo.dwKeySpec,
  121. X509_ASN_ENCODING,
  122. pPubKeyInfo,
  123. &cbPubKeyInfo) )
  124. goto ErrorCryptExportPublicKeyInfo;
  125. // default if we don't have an algid
  126. if(pSignatureAlgorithm == NULL) {
  127. memset(&algID, 0, sizeof(algID));
  128. algID.pszObjId = szOID_OIWSEC_sha1RSASign;
  129. pSignatureAlgorithm = &algID;
  130. }
  131. // make a temp cert, only care about key info
  132. // and serial number for uniqueness
  133. RpcStatus = UuidCreate(&serialNbr);
  134. if (!(RPC_S_OK == RpcStatus || RPC_S_UUID_LOCAL_ONLY == RpcStatus)) {
  135. // Use stack randomness.
  136. ;
  137. }
  138. certInfo.dwVersion = CERT_V3;
  139. certInfo.SubjectPublicKeyInfo = *pPubKeyInfo;
  140. certInfo.SerialNumber.cbData = sizeof(serialNbr);
  141. certInfo.SerialNumber.pbData = (BYTE *) &serialNbr;
  142. certInfo.SignatureAlgorithm = *pSignatureAlgorithm;
  143. certInfo.Issuer = *pSubjectIssuerBlob;
  144. certInfo.Subject = *pSubjectIssuerBlob;
  145. // only put in extensions if we have them
  146. if( pExtensions != NULL) {
  147. certInfo.cExtension = pExtensions->cExtension;
  148. certInfo.rgExtension = pExtensions->rgExtension;
  149. }
  150. //default if we don't have times
  151. if(pStartTime == NULL)
  152. GetSystemTimeAsFileTime(&certInfo.NotBefore);
  153. else if(!SystemTimeToFileTime(pStartTime, &certInfo.NotBefore))
  154. goto ErrorSystemTimeToFileTime;
  155. if(pEndTime == NULL)
  156. *(((DWORDLONG UNALIGNED *) &certInfo.NotAfter)) =
  157. *(((DWORDLONG UNALIGNED *) &certInfo.NotBefore)) +
  158. 0x11F03C3613000i64;
  159. else if(!SystemTimeToFileTime(pEndTime, &certInfo.NotAfter))
  160. goto ErrorSystemTimeToFileTime;
  161. // encode the cert
  162. if( !CryptEncodeObject(
  163. CRYPT_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
  164. &certInfo,
  165. NULL, // pbEncoded
  166. &sigInfo.ToBeSigned.cbData
  167. ) ||
  168. (pbToBeSigned = (BYTE *)
  169. PkiNonzeroAlloc(sigInfo.ToBeSigned.cbData)) == NULL ||
  170. !CryptEncodeObject(
  171. CRYPT_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
  172. &certInfo,
  173. pbToBeSigned,
  174. &sigInfo.ToBeSigned.cbData
  175. ) )
  176. goto ErrorEncodeTempCertToBeSigned;
  177. sigInfo.ToBeSigned.pbData = pbToBeSigned;
  178. // sign the certificate
  179. sigInfo.SignatureAlgorithm = certInfo.SignatureAlgorithm;
  180. // this is to work around an OSS bug of not accepting zero length bit strings
  181. // this is only needed if we don't actually sign the code.
  182. sigInfo.Signature.pbData = (BYTE *) &sigInfo;
  183. sigInfo.Signature.cbData = 1;
  184. if( (CERT_CREATE_SELFSIGN_NO_SIGN & dwFlags) == 0 ) {
  185. if( !CryptSignCertificate(
  186. hProv,
  187. keyProvInfo.dwKeySpec,
  188. CRYPT_ASN_ENCODING,
  189. sigInfo.ToBeSigned.pbData,
  190. sigInfo.ToBeSigned.cbData,
  191. &sigInfo.SignatureAlgorithm,
  192. NULL,
  193. NULL,
  194. &sigInfo.Signature.cbData) ||
  195. (pbSignature = (BYTE *)
  196. PkiNonzeroAlloc(sigInfo.Signature.cbData)) == NULL ||
  197. !CryptSignCertificate(
  198. hProv,
  199. keyProvInfo.dwKeySpec,
  200. CRYPT_ASN_ENCODING,
  201. sigInfo.ToBeSigned.pbData,
  202. sigInfo.ToBeSigned.cbData,
  203. &sigInfo.SignatureAlgorithm,
  204. NULL,
  205. pbSignature,
  206. &sigInfo.Signature.cbData) )
  207. goto ErrorCryptSignCertificate;
  208. sigInfo.Signature.pbData = pbSignature;
  209. }
  210. // encode the final cert.
  211. if( !CryptEncodeObject(
  212. CRYPT_ASN_ENCODING,
  213. X509_CERT,
  214. &sigInfo,
  215. NULL,
  216. &cbCert
  217. ) ||
  218. (pbCert = (BYTE *)
  219. PkiNonzeroAlloc(cbCert)) == NULL ||
  220. !CryptEncodeObject(
  221. CRYPT_ASN_ENCODING,
  222. X509_CERT,
  223. &sigInfo,
  224. pbCert,
  225. &cbCert ) )
  226. goto ErrorEncodeTempCert;
  227. // get a cert context from the encoding
  228. if( (pCertContext = CertCreateCertificateContext(
  229. CRYPT_ASN_ENCODING,
  230. pbCert,
  231. cbCert)) == NULL )
  232. goto ErrorCreateTempCertContext;
  233. if( (CERT_CREATE_SELFSIGN_NO_KEY_INFO & dwFlags) == 0 ) {
  234. // get the key prov info
  235. if(pKeyProvInfo == NULL) {
  236. // get a key prov info from the hProv
  237. if( !CryptGetProvParam( hProv,
  238. PP_NAME,
  239. NULL,
  240. &cb,
  241. 0) ||
  242. (sz = (char *) PkiNonzeroAlloc(cb)) == NULL ||
  243. !CryptGetProvParam( hProv,
  244. PP_NAME,
  245. (BYTE *) sz,
  246. &cb,
  247. 0) )
  248. goto ErrorGetProvName;
  249. keyProvInfo.pwszProvName = MkWStr(sz);
  250. PkiFree(sz);
  251. sz = NULL;
  252. cb = 0;
  253. if( !CryptGetProvParam( hProv,
  254. PP_CONTAINER,
  255. NULL,
  256. &cb,
  257. 0) ||
  258. (sz = (char *) PkiNonzeroAlloc(cb)) == NULL ||
  259. !CryptGetProvParam( hProv,
  260. PP_CONTAINER,
  261. (BYTE *) sz,
  262. &cb,
  263. 0) )
  264. goto ErrorGetContainerName;
  265. keyProvInfo.pwszContainerName = MkWStr(sz);
  266. cb = sizeof(keyProvInfo.dwProvType);
  267. if( !CryptGetProvParam( hProv,
  268. PP_PROVTYPE,
  269. (BYTE *) &keyProvInfo.dwProvType,
  270. &cb,
  271. 0) )
  272. goto ErrorGetProvType;
  273. pKeyProvInfo = &keyProvInfo;
  274. }
  275. // put the key property on the certificate
  276. if( !CertSetCertificateContextProperty(
  277. pCertContext,
  278. CERT_KEY_PROV_INFO_PROP_ID,
  279. 0,
  280. pKeyProvInfo) )
  281. goto ErrorSetTempCertPropError;
  282. }
  283. CommonReturn:
  284. if(hKey != NULL)
  285. CryptDestroyKey(hKey);
  286. if(fFreehProv && hProv != NULL)
  287. CryptReleaseContext(hProv, 0);
  288. if(keyProvInfo.pwszProvName != NULL)
  289. FreeWStr(keyProvInfo.pwszProvName);
  290. if(keyProvInfo.pwszContainerName != NULL)
  291. FreeWStr(keyProvInfo.pwszContainerName);
  292. if(wsz != NULL)
  293. LocalFree(wsz);
  294. PkiFree(pPubKeyInfo);
  295. PkiFree(pbToBeSigned);
  296. PkiFree(pbSignature);
  297. PkiFree(pbCert);
  298. PkiFree(sz);
  299. // don't know if we have an error or not
  300. // but I do know the errBefore is set properly
  301. SetLastError(errBefore);
  302. return(pCertContext);
  303. ErrorReturn:
  304. if(GetLastError() == ERROR_SUCCESS)
  305. SetLastError((DWORD) E_UNEXPECTED);
  306. err = GetLastError();
  307. // We have an error, make sure we set it.
  308. errBefore = GetLastError();
  309. if(pCertContext != NULL)
  310. CertFreeCertificateContext(pCertContext);
  311. pCertContext = NULL;
  312. goto CommonReturn;
  313. TRACE_ERROR(ErrorCryptGenKey);
  314. TRACE_ERROR(ErrorCryptAcquireContext);
  315. TRACE_ERROR(ErrorCryptExportPublicKeyInfo);
  316. TRACE_ERROR(ErrorEncodeTempCertToBeSigned);
  317. TRACE_ERROR(ErrorEncodeTempCert);
  318. TRACE_ERROR(ErrorCreateTempCertContext);
  319. TRACE_ERROR(ErrorGetProvName);
  320. TRACE_ERROR(ErrorGetContainerName);
  321. TRACE_ERROR(ErrorGetProvType);
  322. TRACE_ERROR(ErrorSetTempCertPropError);
  323. TRACE_ERROR(ErrorCryptSignCertificate);
  324. TRACE_ERROR(ErrorSystemTimeToFileTime);
  325. }