OpenSSL:如何设置OCSP服务器来检查第三方证书?

我正在testingCMTS设备的证书吊销function。 这就要求我设置一个OCSP应答器。 因为它只会用于testing,所以我认为OpenSSL提供的最小实现就足够了。

我已经从电缆调制解调器中提取了证书,将其复制到我的PC,并将其转换为PEM格式。 现在我想在OpenSSL OCSP数据库中注册它并启动一个服务器。

我已经完成了所有这些步骤,但是当我做客户端请求时,我的服务器总是以“未知”响应。 这似乎完全不知道我的证书的存在。

如果有人愿意看我的代码,我将不胜感激。 为了方便起见,我创build了一个由所有使用的命令组成的单个脚本,从设置CA直到启动服务器: http : //code.google.com/p/stacked-crooked/source/browse/躯干/杂项/ OpenSSL的/ AllCommands.sh

您还可以find自定义configuration文件和我正在testing的证书: http : //code.google.com/p/stacked-crooked/source/browse/trunk/Misc/OpenSSL/

任何帮助将不胜感激。

如果你有兴趣,这是我的解决scheme。

首先,我放弃了OpenSSL的OCSP应答器。 它不能用于尚未使用自签名CA创build的证书。

然后,我使用OpenCA库创build一个命令行实用程序,该实用程序能够从OSCP请求创buildOCSP响应。 它完全基于文件:使用DER格式的OSCP请求作为input文件运行,并输出一个DER格式的OCSP响应文件。

命令行实用程序的第二个参数是撤销状态:好,已撤销或未知。 响应文件中的证书状态将与传递的参数相同。 这个代码是基于这个例子 ,在这篇文章中由The Rook指出。

最后一步是创build一个build立在命令行实用程序上的HTTP服务器。 我使用Ruby的Merb框架。 一个很好的特性是,可以将请求状态作为一个HTTP url来请求,例如: http : //127.0.0.1 : 5000/good 。

更新

由于上面的链接被打破,我会在这里发布脚本内容:

AllCommands.sh:

################# # Create the CA # ################# # Create folder stucture and default files mkdir -p CA/private mkdir -p CA/newcerts touch CA/index.txt echo "00" >> CA/serial # Create the CA openssl req -new -x509 -keyout ./CA/private/cakey.pem -out ./CA/cacert.pem -days 365 -passin pass:secret1 -passout pass:secret1 -config openssl.cnf ############################## # Create a test certificate # ############################## # Create the request openssl req -batch -config ./openssl.cnf -new -keyout test-certificate.key -out test-certificate.request -days 365 -passin pass:secret1 -passout pass:secret1 # Create the certificate openssl ca -batch -config ./openssl.cnf -policy policy_anything -passin pass:secret1 -out test-certificate.pem -infiles test-certificate.request # Cleanup request file rm test-certificate.request echo "test-certificate.pem has been generated." ################################## # Sign a third party certificate # ################################## # Create a key openssl genrsa -des3 -passout pass:secret1 -out tmp.key 1024 # Remove the password from the key cp tmp.key tmp.key.old openssl rsa -in tmp.key.old -passin pass:secret1 -passout pass:secret1 -out tmp.key rm tmp.key.old # Sign the certificate with this key openssl x509 -days 365 -in thirdparty.pem -signkey tmp.key -passin pass:secret1 -text -out thirdparty-signed.pem # Remove tempfile rm tmp.key ######################################## # Add the signed certificate to the CA # ######################################## # Create the certs dir if it doesn't already exist mkdir -p CA/certs # Copy our signed third party certificate cp thirdparty-signed.pem CA/certs # Create the hash-link cd CA/certs ln -s thirdparty-signed.pem `openssl x509 -hash -noout -in thirdparty-signed.pem`.0 cd - ################################################# # Add the signed certificate to the CA database # ################################################# openssl ca -config openssl.cnf -policy policy_anything -passin pass:secret1 -ss_cert thirdparty-signed.pem #################### # Start the server # #################### # Use test-certificate.pem as response signer. openssl ocsp -CApath ./CA/certs -index CA/index.txt -port 5000 -rkey test-certificate.key -rsigner test-certificate.pem -CA CA/cacert.pem -text # The client request: # $ openssl ocsp -issuer CA/cacert.pem -VAfile test-certificate.pem -cert thirdparty.pem -url http://10.5.5.247:5000 # => Response verify OK # => thirdparty.pem: unknown # This Update: Apr 13 13:00:59 2010 GMT 

openssl.cnf中:

 # # OpenSSL example configuration file. # This is mostly being used for generation of certificate requests. # # This definition stops the following lines choking if HOME isn't # defined. HOME = $ENV::HOME RANDFILE= $ENV::HOME/.rnd # Extra OBJECT IDENTIFIER info: #oid_file= $ENV::HOME/.oid oid_section= new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: # extensions= # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) [ new_oids ] # We can add new OIDs in here for use by 'ca' and 'req'. # Add a simple OID like this: # testoid1=1.2.3.4 # Or use config file substitution like this: # testoid2=${testoid1}.5.6 #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = ./CA # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts# default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL crl = $dir/crl.pem# The current CRL private_key = $dir/private/cakey.pem # The private key RANDFILE = $dir/private/.rand # private random number file x509_extensions = usr_cert # The extentions to add to the cert # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options # Extension copying option: use with caution. # copy_extensions = copy # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs # so this is commented out by default to leave a V1 CRL. # crlnumber must also be commented out to leave a V1 CRL. # crl_extensions = crl_ext default_days = 365 # how long to certify for default_crl_days = 30 # how long before next CRL default_md = sha1 # which md to use. preserve = no # keep passed DN ordering # A few difference way of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_match # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional # For the 'anything' policy # At this point in time, you must list all acceptable 'object' # types. [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional #################################################################### [ req ] default_bits = 1024 default_keyfile = privkey.pem distinguished_name = req_distinguished_name prompt = no attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert # Passwords for private keys if not present they will be prompted for # input_password = secret # output_password = secret # This sets a mask for permitted string types. There are several options. # default: PrintableString, T61String, BMPString. # pkix: PrintableString, BMPString. # utf8only: only UTF8Strings. # nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). # MASK:XXXX a literal mask value. # WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings # so use this option with caution! string_mask = nombstr # req_extensions = v3_req # The extensions to add to a certificate request [ req_attributes ] challengePassword = A challenge password [ req_distinguished_name ] C=DE ST=Oost-Vlaanderen L=Gent O=Corp OU=Testing Team CN=johnsmith [email protected] [ usr_cert ] # These extensions are added when 'ca' signs a request. # This goes against PKIX guidelines but some CAs do it and some software # requires this to avoid interpreting an end user certificate as a CA. basicConstraints=CA:TRUE # Here are some examples of the usage of nsCertType. If it is omitted # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. # nsCertType = server # For an object signing certificate this would be used. # nsCertType = objsign # For normal client use this is typical # nsCertType = client, email # and for everything including object signing: # nsCertType = client, email, objsign # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment # This will be displayed in Netscape's comment listbox. nsComment = "OpenSSL Generated Certificate" # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer # This stuff is for subjectAltName and issuerAltname. # Import the email address. # subjectAltName=email:copy # An alternative to produce certificates that aren't # deprecated according to PKIX. # subjectAltName=email:move # Copy subject details # issuerAltName=issuer:copy #nsCaRevocationUrl= http://www.domain.dom/ca-crl.pem #nsBaseUrl #nsRevocationUrl #nsRenewalUrl #nsCaPolicyUrl #nsSslServerName [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:TRUE keyUsage = nonRepudiation, digitalSignature, keyEncipherment [ v3_ca ] # Extensions for a typical CA # PKIX recommendation. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always # This is what PKIX recommends but some broken software chokes on critical # extensions. #basicConstraints = critical,CA:true # So we do this instead. basicConstraints = CA:true # Key usage: this is typical for a CA certificate. However since it will # prevent it being used as an test self-signed certificate it is best # left out by default. # keyUsage = cRLSign, keyCertSign # Some might want this also # nsCertType = sslCA, emailCA # Include email address in subject alt name: another PKIX recommendation # subjectAltName=email:copy # Copy issuer details # issuerAltName=issuer:copy # DER hex encoding of an extension: beware experts only! # obj=DER:02:03 # Where 'obj' is a standard or added object # You can even override a supported extension: # basicConstraints= critical, DER:30:03:01:01:FF [ crl_ext ] # CRL extensions. # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. # issuerAltName=issuer:copy authorityKeyIdentifier=keyid:always,issuer:always [ proxy_cert_ext ] # These extensions should be added when creating a proxy certificate # This goes against PKIX guidelines but some CAs do it and some software # requires this to avoid interpreting an end user certificate as a CA. basicConstraints=CA:FALSE # Here are some examples of the usage of nsCertType. If it is omitted # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. # nsCertType = server # For an object signing certificate this would be used. # nsCertType = objsign # For normal client use this is typical # nsCertType = client, email # and for everything including object signing: # nsCertType = client, email, objsign # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment # This will be displayed in Netscape's comment listbox. nsComment = "OpenSSL Generated Certificate" # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer:always # This stuff is for subjectAltName and issuerAltname. # Import the email address. # subjectAltName=email:copy # An alternative to produce certificates that aren't # deprecated according to PKIX. # subjectAltName=email:move # Copy subject details # issuerAltName=issuer:copy #nsCaRevocationUrl= http://www.domain.dom/ca-crl.pem #nsBaseUrl #nsRevocationUrl #nsRenewalUrl #nsCaPolicyUrl #nsSslServerName # This really needs to be in place for it to be a proxy certificate. proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo [ my_v3_ext ] basicConstraints = CA:true 

thirdparty.pem:

 Certificate: Data: Version: 3 (0x2) Serial Number: d9:6f:db:ad:33:69:ce:63 Signature Algorithm: sha1WithRSAEncryption Issuer: C=DE, ST=Berlin, L=Berlin, O=AVM GmbH, OU=Euro-DOCSIS, OU=Germany, CN=AVM GmbH Cable Modem Root Certificate Authority Validity Not Before: Jan 20 13:28:06 2010 GMT Not After : Jun 7 13:28:06 2037 GMT Subject: C=DE, O=AVM GmbH, OU=Euro-DOCSIS, CN=00:04:0E:C4:AE:94 Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:d5:73:b6:23:c6:23:ff:97:25:84:21:b7:25:f1: 8f:f7:c1:ae:dc:13:ea:56:69:c1:f4:9c:74:d7:b8: 50:74:2b:0b:4c:56:0f:ab:8e:b3:8e:04:26:74:e6: 7c:8d:23:2e:34:74:6c:cc:d6:d6:81:b1:ba:1a:ed: 80:fa:fd:c5:65:09:23:5e:6d:b9:15:9e:52:9f:d2: 66:f7:3d:b9:4b:2b:ef:ab:80:72:26:47:24:17:35: c9:2a:c7:df:53:a6:15:c0:f4:b7:bc:40:37:29:51: c5:50:9a:90:d8:af:56:42:9a:07:3c:8c:77:f0:93: 09:c8:0b:52:7a:3d:64:5f:d9 Exponent: 65537 (0x10001) Signature Algorithm: sha1WithRSAEncryption 27:64:a3:d5:76:d2:86:32:6e:c0:e5:45:39:1f:2a:1a:04:d9: 46:d9:92:ee:71:a1:7d:07:77:ac:1a:0f:2a:e2:a1:3c:d2:aa: 13:e2:df:55:6a:3c:93:54:e4:63:b8:5d:3c:6b:97:3b:b2:2e: e6:c0:17:6c:6b:e2:0c:ea:66:48:42:02:f3:41:d2:cc:ca:ed: 64:a6:b9:78:97:b3:df:87:75:61:fb:86:49:18:03:86:7c:4c: 89:cc:ba:6b:6d:ad:6c:4b:da:ad:1c:65:b8:42:9d:ad:c5:b1: 35:60:36:b4:e2:1f:a3:c9:74:e4:34:3a:b5:d2:d6:1c:80:97: 4d:8f:b3:ab:c4:35:95:c4:ca:e5:93:2b:dc:36:54:51:04:d3: ea:34:c6:2f:7b:fd:7e:24:04:35:9d:c2:6b:59:e0:ef:dc:0e: 6b:27:96:d3:9c:63:87:4d:c3:17:b6:4b:24:39:25:08:4e:d8: 0e:14:8f:a9:8d:63:ff:74:d3:62:de:d7:11:71:e6:fd:fc:94: 0d:77:27:9f:a3:e5:4c:84:9b:7a:d0:4b:6e:ba:b6:d5:35:9b: 97:2f:c4:ff:b9:6b:fa:de:50:2f:38:12:4f:40:2c:55:8c:e7: db:42:fc:df:f9:65:74:52:81:42:b0:88:c8:9b:0f:9b:09:93: de:ae:e1:19 -----BEGIN CERTIFICATE----- MIIC9DCCAdygAwIBAgIJANlv260zac5jMA0GCSqGSIb3DQEBBQUAMIGkMQswCQYD VQQGEwJERTEPMA0GA1UECBMGQmVybGluMQ8wDQYDVQQHEwZCZXJsaW4xETAPBgNV BAoTCEFWTSBHbWJIMRQwEgYDVQQLEwtFdXJvLURPQ1NJUzEQMA4GA1UECxMHR2Vy bWFueTE4MDYGA1UEAxMvQVZNIEdtYkggQ2FibGUgTW9kZW0gUm9vdCBDZXJ0aWZp Y2F0ZSBBdXRob3JpdHkwHhcNMTAwMTIwMTMyODA2WhcNMzcwNjA3MTMyODA2WjBS MQswCQYDVQQGEwJERTERMA8GA1UEChMIQVZNIEdtYkgxFDASBgNVBAsTC0V1cm8t RE9DU0lTMRowGAYDVQQDExEwMDowNDowRTpDNDpBRTo5NDCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEA1XO2I8Yj/5clhCG3JfGP98Gu3BPqVmnB9Jx017hQdCsL TFYPq46zjgQmdOZ8jSMuNHRszNbWgbG6Gu2A+v3FZQkjXm25FZ5Sn9Jm9z25Syvv q4ByJkckFzXJKsffU6YVwPS3vEA3KVHFUJqQ2K9WQpoHPIx38JMJyAtSej1kX9kC AwEAATANBgkqhkiG9w0BAQUFAAOCAQEAJ2Sj1XbShjJuwOVFOR8qGgTZRtmS7nGh fQd3rBoPKuKhPNKqE+LfVWo8k1TkY7hdPGuXO7Iu5sAXbGviDOpmSEIC80HSzMrt ZKa5eJez34d1YfuGSRgDhnxMicy6a22tbEvarRxluEKdrcWxNWA2tOIfo8l05DQ6 tdLWHICXTY+zq8Q1lcTK5ZMr3DZUUQTT6jTGL3v9fiQENZ3Ca1ng79wOayeW05xj h03DF7ZLJDklCE7YDhSPqY1j/3TTYt7XEXHm/fyUDXcnn6PlTISbetBLbrq21TWb ly/E/7lr+t5QLzgST0AsVYzn20L83/lldFKBQrCIyJsPmwmT3q7hGQ== -----END CERTIFICATE----- 

使用OpenCA库的命令行实用程序是用C:

 #include <libpki/pki.h> PKI_X509_OCSP_REQ * CreateOCSPRequest(PKI_X509_CERT * cacert, long long serial) { PKI_X509_OCSP_REQ *request = NULL; request = PKI_X509_OCSP_REQ_new(); if (request == NULL ) { printf("Memory Errorequest!"); exit(1); } // Adds the details about certificate (serial issued by cacert) if (PKI_X509_OCSP_REQ_add_longlong( request, serial, cacert, NULL) == PKI_ERR) { printf ("Can not add serial!"); exit (1); } if (PKI_X509_OCSP_REQ_add_nonce(request, 0) == PKI_ERR ) { printf ("Can not add NONCE to REQUEST!"); exit(1); } return request; } PKI_X509_OCSP_RESP * CreateOCSPResponse(PKI_X509_OCSP_REQ *request, PKI_OCSP_CERTSTATUS ocspStatus) { PKI_X509_OCSP_RESP * resp = NULL; PKI_OCSP_CERTID *cid = NULL; // Create a new OCSP response if ((resp = PKI_X509_OCSP_RESP_new()) == NULL) { printf("Memory allocation errorequest!\n"); exit (1); } // Now, let's set the status of the response if (PKI_X509_OCSP_RESP_set_status(resp, PKI_X509_OCSP_RESP_STATUS_SUCCESSFUL) == PKI_ERR) { printf("ERROR: setting response status failed.\n"); exit (1); } printf ("Set response status.\n"); // We now want to copy the NONCE from the request... if (PKI_X509_OCSP_RESP_copy_nonce(resp, request) == PKI_ERR) { printf("ERROR::can not copy NONCE!!!\n"); exit (1); } printf ("Added NONCE.\n"); // We also need the Certificate Identifier from the request if ((cid = PKI_X509_OCSP_REQ_get_cid(request, 0)) == NULL) { printf("Can not get CID from request!\n"); exit (1); } // Let's add the status of the requested certificate to the response int ret = PKI_ERR; if (ocspStatus == PKI_OCSP_CERTSTATUS_REVOKED) { PKI_TIME * revocationTime = PKI_TIME_new(0); PKI_TIME * thisUpdate = PKI_TIME_new(100); PKI_TIME * nextUpdate = PKI_TIME_new(200); ret = PKI_X509_OCSP_RESP_add(resp, cid, ocspStatus, revocationTime, thisUpdate, nextUpdate, CRL_REASON_KEY_COMPROMISE, NULL); PKI_TIME_free(revocationTime); PKI_TIME_free(thisUpdate); PKI_TIME_free(nextUpdate); } else { ret = PKI_X509_OCSP_RESP_add(resp, cid, ocspStatus, NULL, NULL, NULL, CRL_REASON_UNSPECIFIED, NULL); } if (ret == PKI_ERR) { printf("Add CID to response failed!\n"); exit (1); } printf ("Added CID.\n"); return resp; } PKI_X509_CERT * ReadCertificate(char * file) { PKI_X509_CERT * cert = NULL; if ((cert = PKI_X509_CERT_get(file, NULL, NULL)) == NULL) { printf("Failed to load certificate: %s\n", file); exit(1); } return cert; } void SignResponse(PKI_X509_OCSP_RESP * resp) { PKI_X509_KEYPAIR * keyPair = PKI_X509_KEYPAIR_get("root.key", NULL, NULL); if (!keyPair) { printf("Obtaining keypair from root.key failed!"); exit (1); } PKI_X509_CERT * caCertificate = ReadCertificate("CA/cacert.pem"); PKI_X509_CERT * signerCertificate = ReadCertificate("root.pem"); PKI_X509_OCSP_RESP_sign(resp, keyPair, signerCertificate, caCertificate, NULL, NULL); } void genresponse(PKI_OCSP_CERTSTATUS ocspStatus) { PKI_X509_OCSP_REQ *request = NULL; PKI_X509_OCSP_RESP * resp = NULL; PKI_X509_CERT * cacert = NULL; PKI_TOKEN * tk = NULL; if ((request = PKI_X509_OCSP_REQ_get("req.der", NULL, NULL)) == NULL) { printf("ERROR, can't load req.der!\n"); exit(1); } resp = CreateOCSPResponse(request, ocspStatus); // Now sign the response SignResponse(resp); printf("Response has been signed.\n"); PKI_X509_OCSP_RESP_put(resp, PKI_DATA_FORMAT_ASN1, "resp.der", NULL, NULL, NULL); printf("Response file resp.der has been written.\n"); } void genrequest(long long serial) { PKI_X509_OCSP_REQ *request = NULL; PKI_X509_OCSP_RESP * resp = NULL; PKI_X509_CERT * cacert = NULL; if ((cacert = PKI_X509_CERT_get("cacert.pem", NULL, NULL)) == NULL) { printf("ERROR, can not load cacert.pem!\n"); exit(1); } request = CreateOCSPRequest(cacert, serial); PKI_X509_OCSP_REQ_put(request, PKI_DATA_FORMAT_ASN1, "req.der", NULL, NULL, NULL); printf("req.der written.\n"); } void PrintUsage() { printf("Usage: ocsp { genrequest <serial> | genresponse <good | revoked | unknown> } \n"); } /** * Main function * */ int main(int argc, char** argv) { PKI_init_all(); if (argc < 3) { PrintUsage(); exit(1); } if (0 == strcmp(argv[1], "genrequest")) { long long serial = 0; sscanf(argv[2], "%lld", &serial); genrequest(serial); } else if (0 == strcmp(argv[1], "genresponse")) { PKI_OCSP_CERTSTATUS certStatus = -1; if (0 == strcmp(argv[2], "good")) { certStatus = PKI_OCSP_CERTSTATUS_GOOD; } else if (0 == strcmp(argv[2], "revoked")) { certStatus = PKI_OCSP_CERTSTATUS_REVOKED; } else if (0 == strcmp(argv[2], "unknown")) { certStatus = PKI_OCSP_CERTSTATUS_UNKNOWN; } else { printf("Unknown response type: %s.\n", argv[2]); PrintUsage(); exit(1); } genresponse(certStatus); } else { PrintUsage(); exit(1); } return 0; }