/* MakeAliceRsaPss.c */
/* Create an X.509 certificate for Alice using RSA-PSS-SHA256 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "diCrPKI.h"
#ifdef NDEBUG
/* Make sure assertion testing is turned on */
#undef NDEBUG
#endif
#include <assert.h>
/* Link with `diCrPKI.lib`.
* In MSVC set
* Configuration Properties > Linker > Input > Additional Dependencies=diCrPKI.lib;
*/
static void pr_x509dump(const char *certname);
int main(void)
{
/* Required input files */
const char *issuercert = "CarlRSAPssSelf.cer"; // Carl the CA's certificate
const char *issuerkey = "CarlRSAPSS.p8e"; // Carl's encrypted private key
const char *subjectpubkey = "AliceRSAPSS.pub"; // Alice's public key
/* Name of output certificate file to be created */
const char *certfile = "AliceRsaPssSignByCarl.cer";
char ski[PKI_SHA1_CHARS + 1]; /* Buffer for SHA-1 digest of public key*/
char extnbuf[512];
char *query;
char qrybuf[128];
char *keystr;
long r, nchars;
/* Other fixed parameters */
const char *dn = "CN=AliceRSA;O=PSS;"; // Distinguished name
/* Set a fixed serial number and validity dates */
const char *extns =
"rfc822name=AliceRSA@example.com;"
"serialNumber=#x47346BC7800056BC11D36E2EC410B3B0;"
"notBefore=2018-04-01;"
"notAfter=2039-12-31;"
"subjectKeyIdentifier=" // Value to be added
;
/* Set required key usage flags */
long ku = PKI_X509_KEYUSAGE_DIGITALSIGNATURE | PKI_X509_KEYUSAGE_NONREPUDIATION;
/* Show we have the latest version of the core DLL */
printf("PKI_Version=%ld\n", PKI_Version(0, 0));
/* Compute SubjectKeyIdentifier from public key file (see RFC5280 s4.2.1.2)
(1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
value of the BIT STRING subjectPublicKey (excluding the tag,
length, and number of unused bits).
-- this is exactly the contents of the RSAPublicKey public key file created
-- by this Toolkit.
*/
r = HASH_HexFromFile(ski, sizeof(ski) - 1, subjectpubkey, PKI_HASH_SHA1);
printf("SKI=%s\n", ski);
/* Compose Extensions parameter by appending the SKI value in hex */
strcpy_s(extnbuf, sizeof(extnbuf), extns);
strcat_s(extnbuf, sizeof(extnbuf), ski);
strcat_s(extnbuf, sizeof(extnbuf), ";");
printf("extns=[%s]\n", extnbuf);
/* Create X.509 certificate file
* using RSA-PSS-256 signature algorithm but setting the PSS parameter salt length to zero
* so we get the same result each time.
* Hint: this is for demonstration purposes. Use the default salt length in practice.
*/
r = X509_MakeCert(certfile, issuercert, subjectpubkey, issuerkey, 0, 0, dn, extnbuf, ku, "password",
PKI_SIG_RSA_PSS_SHA256 | PKI_PSS_SALTLEN_ZERO | PKI_X509_AUTHKEYID);
printf("X509_MakeCert(0 returns %ld (expecting 0)\n", r);
assert(0 == r);
/* Dump details about this new certificate */
pr_x509dump(certfile);
/* Expected output:
FILE: AliceRsaPssSignByCarl.cer
X.509 CERTIFICATE
Version: 3
Serial Number:
#x47346BC7800056BC11D36E2EC410B3B0
Issuer:
CN=CarlRSA;O=PSS
Subject:
CN=AliceRSA;O=PSS
-----[cut]-----
SHA-256 Thumbprint:
4a4783c4ed1be9052a3170f70ae1e24dde5da79a9df816e6b1f522203bccfbbf
*/
/* Query some information from it */
/* Expected output:
X509_QueryCert(signatureAlgorithm)=rsaPSS
X509_QueryCert(hashAlgorithm)=sha256
X509_QueryCert(pssParams)=sha256/mgf1SHA256/0/trailerFieldBC
*/
query = "signatureAlgorithm";
X509_QueryCert(qrybuf, sizeof(qrybuf) - 1, certfile, query, 0);
printf("X509_QueryCert(%s)=%s\n", query, qrybuf);
query = "hashAlgorithm";
X509_QueryCert(qrybuf, sizeof(qrybuf) - 1, certfile, query, 0);
printf("X509_QueryCert(%s)=%s\n", query, qrybuf);
query = "pssParams";
X509_QueryCert(qrybuf, sizeof(qrybuf) - 1, certfile, query, 0);
printf("X509_QueryCert(%s)=%s\n", query, qrybuf);
/* Show we can extract Alice's public key from it */
nchars = RSA_ReadAnyPublicKey(NULL, 0, certfile, 0);
assert(nchars > 0);
// Read into an internal key string
keystr = malloc(nchars + 1);
assert(keystr);
nchars = RSA_ReadAnyPublicKey(keystr, nchars, certfile, 0);
printf("Key length=%ld bits\n", RSA_KeyBits(keystr)); // Key length=2048 bits
free(keystr);
}
/// Dump details of X.509 file to stdout
static void pr_x509dump(const char *certname)
{
char *buf;
long nchars;
printf("FILE: %s\n", certname);
// New function in v12
nchars = X509_TextDumpToString(NULL, 0, certname, 0);
if (nchars <= 0) {
printf("**ERROR %ld\n", nchars);
return;
}
buf = malloc(nchars + 1);
assert(buf);
nchars = X509_TextDumpToString(buf, nchars, certname, 0);
printf("%s\n", buf);
free(buf);
}