/* * Public API to return a binary buffer from a cert. Suitable to send * over the wire. Caller must free 'out' if this function returns success (0) * Parse .pem files according to http://www.faqs.org/rfcs/rfc1421.html */ int32 matrixX509ReadCert(psPool_t *pool, const char *fileName, unsigned char **out, int32 *outLen, sslChainLen_t *chain) { int32 certBufLen, rc, certChainLen, i; unsigned char *oneCert[MAX_CHAIN_LENGTH]; unsigned char *certPtr, *tmp; char *certFile, *start, *end, *certBuf; const char sep[] = ";"; /* Init chain array and output params */ for (i=0; i < MAX_CHAIN_LENGTH; i++) { oneCert[i] = NULL; (*chain)[i] = 0; } *outLen = certChainLen = i = 0; rc = -1; /* For PKI product purposes, this routine now accepts a chain of certs. */ if (fileName != NULL) { fileName += parseList(pool, fileName, sep, &certFile); } else { return 0; } while (certFile != NULL) { if (i == MAX_CHAIN_LENGTH) { matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n", MAX_CHAIN_LENGTH); psFree(certFile); rc = -1; goto err; } if ((rc = psGetFileBin(pool, certFile, (unsigned char**)&certBuf, &certBufLen)) < 0) { matrixStrDebugMsg("Couldn't open file %s\n", certFile); goto err; } psFree(certFile); certPtr = (unsigned char*)certBuf; start = end = certBuf; while (certBufLen > 0) { if (((start = strstr(certBuf, "-----BEGIN")) != NULL) && ((start = strstr(certBuf, "CERTIFICATE-----")) != NULL) && (end = strstr(start, "-----END")) != NULL) { start += strlen("CERTIFICATE-----"); (*chain)[i] = (int32)(end - start); end += strlen("-----END CERTIFICATE-----"); while (*end == '\r' || *end == '\n' || *end == '\t' || *end == ' ') { end++; } } else { psFree(certPtr); rc = -1; goto err; } oneCert[i] = psMalloc(pool, (*chain)[i]); certBufLen -= (int32)(end - certBuf); certBuf = end; memset(oneCert[i], '\0', (*chain)[i]); if (ps_base64_decode((unsigned char*)start, (*chain)[i], oneCert[i], &(*chain)[i]) != 0) { psFree(certPtr); matrixStrDebugMsg("Unable to base64 decode certificate\n", NULL); rc = -1; goto err; } certChainLen += (*chain)[i]; i++; if (i == MAX_CHAIN_LENGTH) { matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n", MAX_CHAIN_LENGTH); psFree(certPtr); rc = -1; goto err; } } psFree(certPtr); /* Check for more files */ fileName += parseList(pool, fileName, sep, &certFile); } *outLen = certChainLen; /* Don't bother stringing them together if only one was passed in */ if (i == 1) { sslAssert(certChainLen == (*chain)[0]); *out = oneCert[0]; return 0; } else { *out = tmp = psMalloc(pool, certChainLen); for (i=0; i < MAX_CHAIN_LENGTH; i++) { if (oneCert[i]) { memcpy(tmp, oneCert[i], (*chain)[i]); tmp += (*chain)[i]; } } rc = 0; } err: for (i=0; i < MAX_CHAIN_LENGTH; i++) { if (oneCert[i]) psFree(oneCert[i]); } return rc; }
/* * Public API to return an ASN.1 encoded key stream from a PEM private * key file * * If password is provided, we only deal with 3des cbc encryption * Function allocates key on success. User must free. */ int32 matrixRsaReadPrivKey(psPool_t *pool, const char *fileName, const char *password, unsigned char **keyMem, int32 *keyMemLen) { unsigned char *keyBuf, *DERout, *start, *end; int32 keyBufLen, rc, DERlen, PEMlen = 0; #ifdef USE_3DES sslCipherContext_t ctx; unsigned char passKey[SSL_DES3_KEY_LEN]; unsigned char cipherIV[SSL_DES3_IV_LEN]; int32 tmp, encrypted = 0; #endif /* USE_3DES */ if (fileName == NULL) { return 0; } *keyMem = NULL; if ((rc = psGetFileBin(pool, fileName, &keyBuf, &keyBufLen)) < 0) { return rc; } start = end = NULL; /* * Check header and encryption parameters. */ if ((start = strstr(keyBuf, "-----BEGIN RSA PRIVATE KEY-----")) == NULL) { matrixStrDebugMsg("Error parsing private key buffer\n", NULL); psFree(keyBuf); return -1; } start += strlen("-----BEGIN RSA PRIVATE KEY-----"); while (*start == '\r' || *start == '\n') { start++; } if (strstr(keyBuf, "Proc-Type:") && strstr(keyBuf, "4,ENCRYPTED")) { #ifdef USE_3DES encrypted++; if (password == NULL) { matrixStrDebugMsg("No password given for encrypted private key\n", NULL); psFree(keyBuf); return -1; } if ((start = strstr(keyBuf, encryptHeader)) == NULL) { matrixStrDebugMsg("Unrecognized private key file encoding\n", NULL); psFree(keyBuf); return -1; } start += strlen(encryptHeader); /* SECURITY - we assume here that header points to at least 16 bytes of data */ tmp = hexToBinary((unsigned char*)start, cipherIV, SSL_DES3_IV_LEN); if (tmp < 0) { matrixStrDebugMsg("Invalid private key file salt\n", NULL); psFree(keyBuf); return -1; } start += tmp; generate3DESKey((unsigned char*)password, (int32)strlen(password), cipherIV, (unsigned char*)passKey); #else /* !USE_3DES */ /* * The private key is encrypted, but 3DES support has been turned off */ matrixStrDebugMsg("3DES has been disabled for private key decrypt\n", NULL); psFree(keyBuf); return -1; #endif /* USE_3DES */ } if ((end = strstr(keyBuf, "-----END RSA PRIVATE KEY-----")) == NULL) { matrixStrDebugMsg("Error parsing private key buffer\n", NULL); psFree(keyBuf); return -1; } PEMlen = (int32)(end - start); /* Take the raw input and do a base64 decode */ DERout = psMalloc(pool, PEMlen); if (DERout == NULL) { return -8; /* SSL_MEM_ERROR */ } DERlen = PEMlen; if (ps_base64_decode(start, PEMlen, DERout, (uint32*)&DERlen) != 0) { psFree(DERout); psFree(keyBuf); matrixStrDebugMsg("Unable to base64 decode private key\n", NULL); return -1; } psFree(keyBuf); #ifdef USE_3DES /* * Decode */ if (encrypted == 1 && password) { matrix3desInit(&ctx, cipherIV, passKey, SSL_DES3_KEY_LEN); matrix3desDecrypt(&ctx, DERout, DERout, DERlen); } #endif /* USE_3DES */ /* Don't parse this here. Return the ASN.1 encoded buf to be consistent with the other mem APIs. Use the ParsePrivKey function if you want the structure format */ *keyMem = DERout; *keyMemLen = DERlen; return rc; }