From 37a8d409f8ffc065c1b1417f0f3b5ba050e8aa95 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 5 Nov 2012 13:57:22 -0800 Subject: Imported Upstream version 1.0.1c --- demos/README | 9 + demos/asn1/README.ASN1 | 7 + demos/asn1/ocsp.c | 366 +++++ demos/b64.c | 268 ++++ demos/b64.pl | 20 + demos/bio/Makefile | 16 + demos/bio/README | 3 + demos/bio/saccept.c | 112 ++ demos/bio/sconnect.c | 121 ++ demos/bio/server.pem | 30 + demos/cms/cacert.pem | 18 + demos/cms/cakey.pem | 15 + demos/cms/cms_comp.c | 61 + demos/cms/cms_ddec.c | 89 ++ demos/cms/cms_dec.c | 79 + demos/cms/cms_denc.c | 97 ++ demos/cms/cms_enc.c | 92 ++ demos/cms/cms_sign.c | 89 ++ demos/cms/cms_sign2.c | 103 ++ demos/cms/cms_uncomp.c | 56 + demos/cms/cms_ver.c | 87 ++ demos/cms/comp.txt | 22 + demos/cms/encr.txt | 3 + demos/cms/sign.txt | 3 + demos/cms/signer.pem | 32 + demos/cms/signer2.pem | 32 + demos/easy_tls/Makefile | 123 ++ demos/easy_tls/README | 65 + demos/easy_tls/cacerts.pem | 18 + demos/easy_tls/cert.pem | 31 + demos/easy_tls/easy-tls.c | 1240 +++++++++++++++ demos/easy_tls/easy-tls.h | 57 + demos/easy_tls/test.c | 244 +++ demos/easy_tls/test.h | 11 + demos/eay/Makefile | 24 + demos/eay/base64.c | 49 + demos/eay/conn.c | 105 ++ demos/eay/loadrsa.c | 53 + demos/engines/cluster_labs/Makefile | 114 ++ demos/engines/cluster_labs/cluster_labs.h | 35 + demos/engines/cluster_labs/hw_cluster_labs.c | 721 +++++++++ demos/engines/cluster_labs/hw_cluster_labs.ec | 8 + demos/engines/cluster_labs/hw_cluster_labs_err.c | 151 ++ demos/engines/cluster_labs/hw_cluster_labs_err.h | 99 ++ demos/engines/ibmca/Makefile | 114 ++ demos/engines/ibmca/hw_ibmca.c | 920 ++++++++++++ demos/engines/ibmca/hw_ibmca.ec | 8 + demos/engines/ibmca/hw_ibmca_err.c | 154 ++ demos/engines/ibmca/hw_ibmca_err.h | 102 ++ demos/engines/ibmca/ica_openssl_api.h | 189 +++ demos/engines/rsaref/Makefile | 135 ++ demos/engines/rsaref/README | 22 + demos/engines/rsaref/build.com | 105 ++ demos/engines/rsaref/rsaref.c | 685 +++++++++ demos/engines/rsaref/rsaref.ec | 8 + demos/engines/rsaref/rsaref_err.c | 161 ++ demos/engines/rsaref/rsaref_err.h | 109 ++ demos/engines/zencod/Makefile | 114 ++ demos/engines/zencod/hw_zencod.c | 1739 ++++++++++++++++++++++ demos/engines/zencod/hw_zencod.ec | 8 + demos/engines/zencod/hw_zencod.h | 160 ++ demos/engines/zencod/hw_zencod_err.c | 151 ++ demos/engines/zencod/hw_zencod_err.h | 99 ++ demos/maurice/Makefile | 59 + demos/maurice/README | 34 + demos/maurice/cert.pem | 77 + demos/maurice/example1.c | 198 +++ demos/maurice/example2.c | 75 + demos/maurice/example3.c | 87 ++ demos/maurice/example4.c | 123 ++ demos/maurice/loadkeys.c | 72 + demos/maurice/loadkeys.h | 19 + demos/maurice/privkey.pem | 27 + demos/pkcs12/README | 3 + demos/pkcs12/pkread.c | 61 + demos/pkcs12/pkwrite.c | 46 + demos/prime/Makefile | 20 + demos/prime/prime.c | 101 ++ demos/privkey.pem | 9 + demos/selfsign.c | 180 +++ demos/sign/Makefile | 15 + demos/sign/cert.pem | 14 + demos/sign/key.pem | 9 + demos/sign/sig.txt | 158 ++ demos/sign/sign.c | 153 ++ demos/sign/sign.txt | 170 +++ demos/smime/cacert.pem | 18 + demos/smime/cakey.pem | 15 + demos/smime/encr.txt | 3 + demos/smime/sign.txt | 3 + demos/smime/signer.pem | 32 + demos/smime/signer2.pem | 32 + demos/smime/smdec.c | 83 ++ demos/smime/smenc.c | 92 ++ demos/smime/smsign.c | 89 ++ demos/smime/smsign2.c | 107 ++ demos/smime/smver.c | 87 ++ demos/spkigen.c | 161 ++ demos/ssl/cli.cpp | 110 ++ demos/ssl/inetdsrv.cpp | 98 ++ demos/ssl/serv.cpp | 152 ++ demos/ssltest-ecc/ECC-RSAcertgen.sh | 98 ++ demos/ssltest-ecc/ECCcertgen.sh | 164 ++ demos/ssltest-ecc/README | 15 + demos/ssltest-ecc/RSAcertgen.sh | 121 ++ demos/ssltest-ecc/ssltest.sh | 188 +++ demos/state_machine/Makefile | 9 + demos/state_machine/state_machine.c | 416 ++++++ demos/tunala/A-client.pem | 84 ++ demos/tunala/A-server.pem | 84 ++ demos/tunala/CA.pem | 24 + demos/tunala/INSTALL | 107 ++ demos/tunala/Makefile | 41 + demos/tunala/Makefile.am | 7 + demos/tunala/README | 233 +++ demos/tunala/autogunk.sh | 25 + demos/tunala/autoungunk.sh | 19 + demos/tunala/breakage.c | 66 + demos/tunala/buffer.c | 205 +++ demos/tunala/cb.c | 162 ++ demos/tunala/configure.in | 29 + demos/tunala/ip.c | 146 ++ demos/tunala/sm.c | 151 ++ demos/tunala/test.sh | 107 ++ demos/tunala/tunala.c | 1109 ++++++++++++++ demos/tunala/tunala.h | 215 +++ demos/x509/README | 3 + demos/x509/mkcert.c | 172 +++ demos/x509/mkreq.c | 161 ++ 129 files changed, 16914 insertions(+) create mode 100644 demos/README create mode 100644 demos/asn1/README.ASN1 create mode 100644 demos/asn1/ocsp.c create mode 100644 demos/b64.c create mode 100644 demos/b64.pl create mode 100644 demos/bio/Makefile create mode 100644 demos/bio/README create mode 100644 demos/bio/saccept.c create mode 100644 demos/bio/sconnect.c create mode 100644 demos/bio/server.pem create mode 100644 demos/cms/cacert.pem create mode 100644 demos/cms/cakey.pem create mode 100644 demos/cms/cms_comp.c create mode 100644 demos/cms/cms_ddec.c create mode 100644 demos/cms/cms_dec.c create mode 100644 demos/cms/cms_denc.c create mode 100644 demos/cms/cms_enc.c create mode 100644 demos/cms/cms_sign.c create mode 100644 demos/cms/cms_sign2.c create mode 100644 demos/cms/cms_uncomp.c create mode 100644 demos/cms/cms_ver.c create mode 100644 demos/cms/comp.txt create mode 100644 demos/cms/encr.txt create mode 100644 demos/cms/sign.txt create mode 100644 demos/cms/signer.pem create mode 100644 demos/cms/signer2.pem create mode 100644 demos/easy_tls/Makefile create mode 100644 demos/easy_tls/README create mode 100644 demos/easy_tls/cacerts.pem create mode 100644 demos/easy_tls/cert.pem create mode 100644 demos/easy_tls/easy-tls.c create mode 100644 demos/easy_tls/easy-tls.h create mode 100644 demos/easy_tls/test.c create mode 100644 demos/easy_tls/test.h create mode 100644 demos/eay/Makefile create mode 100644 demos/eay/base64.c create mode 100644 demos/eay/conn.c create mode 100644 demos/eay/loadrsa.c create mode 100644 demos/engines/cluster_labs/Makefile create mode 100644 demos/engines/cluster_labs/cluster_labs.h create mode 100644 demos/engines/cluster_labs/hw_cluster_labs.c create mode 100644 demos/engines/cluster_labs/hw_cluster_labs.ec create mode 100644 demos/engines/cluster_labs/hw_cluster_labs_err.c create mode 100644 demos/engines/cluster_labs/hw_cluster_labs_err.h create mode 100644 demos/engines/ibmca/Makefile create mode 100644 demos/engines/ibmca/hw_ibmca.c create mode 100644 demos/engines/ibmca/hw_ibmca.ec create mode 100644 demos/engines/ibmca/hw_ibmca_err.c create mode 100644 demos/engines/ibmca/hw_ibmca_err.h create mode 100644 demos/engines/ibmca/ica_openssl_api.h create mode 100644 demos/engines/rsaref/Makefile create mode 100644 demos/engines/rsaref/README create mode 100644 demos/engines/rsaref/build.com create mode 100644 demos/engines/rsaref/rsaref.c create mode 100644 demos/engines/rsaref/rsaref.ec create mode 100644 demos/engines/rsaref/rsaref_err.c create mode 100644 demos/engines/rsaref/rsaref_err.h create mode 100644 demos/engines/zencod/Makefile create mode 100644 demos/engines/zencod/hw_zencod.c create mode 100644 demos/engines/zencod/hw_zencod.ec create mode 100644 demos/engines/zencod/hw_zencod.h create mode 100644 demos/engines/zencod/hw_zencod_err.c create mode 100644 demos/engines/zencod/hw_zencod_err.h create mode 100644 demos/maurice/Makefile create mode 100644 demos/maurice/README create mode 100644 demos/maurice/cert.pem create mode 100644 demos/maurice/example1.c create mode 100644 demos/maurice/example2.c create mode 100644 demos/maurice/example3.c create mode 100644 demos/maurice/example4.c create mode 100644 demos/maurice/loadkeys.c create mode 100644 demos/maurice/loadkeys.h create mode 100644 demos/maurice/privkey.pem create mode 100644 demos/pkcs12/README create mode 100644 demos/pkcs12/pkread.c create mode 100644 demos/pkcs12/pkwrite.c create mode 100644 demos/prime/Makefile create mode 100644 demos/prime/prime.c create mode 100644 demos/privkey.pem create mode 100644 demos/selfsign.c create mode 100644 demos/sign/Makefile create mode 100644 demos/sign/cert.pem create mode 100644 demos/sign/key.pem create mode 100644 demos/sign/sig.txt create mode 100644 demos/sign/sign.c create mode 100644 demos/sign/sign.txt create mode 100644 demos/smime/cacert.pem create mode 100644 demos/smime/cakey.pem create mode 100644 demos/smime/encr.txt create mode 100644 demos/smime/sign.txt create mode 100644 demos/smime/signer.pem create mode 100644 demos/smime/signer2.pem create mode 100644 demos/smime/smdec.c create mode 100644 demos/smime/smenc.c create mode 100644 demos/smime/smsign.c create mode 100644 demos/smime/smsign2.c create mode 100644 demos/smime/smver.c create mode 100644 demos/spkigen.c create mode 100644 demos/ssl/cli.cpp create mode 100644 demos/ssl/inetdsrv.cpp create mode 100644 demos/ssl/serv.cpp create mode 100755 demos/ssltest-ecc/ECC-RSAcertgen.sh create mode 100755 demos/ssltest-ecc/ECCcertgen.sh create mode 100644 demos/ssltest-ecc/README create mode 100755 demos/ssltest-ecc/RSAcertgen.sh create mode 100755 demos/ssltest-ecc/ssltest.sh create mode 100644 demos/state_machine/Makefile create mode 100644 demos/state_machine/state_machine.c create mode 100644 demos/tunala/A-client.pem create mode 100644 demos/tunala/A-server.pem create mode 100644 demos/tunala/CA.pem create mode 100644 demos/tunala/INSTALL create mode 100644 demos/tunala/Makefile create mode 100644 demos/tunala/Makefile.am create mode 100644 demos/tunala/README create mode 100755 demos/tunala/autogunk.sh create mode 100755 demos/tunala/autoungunk.sh create mode 100644 demos/tunala/breakage.c create mode 100644 demos/tunala/buffer.c create mode 100644 demos/tunala/cb.c create mode 100644 demos/tunala/configure.in create mode 100644 demos/tunala/ip.c create mode 100644 demos/tunala/sm.c create mode 100755 demos/tunala/test.sh create mode 100644 demos/tunala/tunala.c create mode 100644 demos/tunala/tunala.h create mode 100644 demos/x509/README create mode 100644 demos/x509/mkcert.c create mode 100644 demos/x509/mkreq.c (limited to 'demos') diff --git a/demos/README b/demos/README new file mode 100644 index 0000000..d2155ef --- /dev/null +++ b/demos/README @@ -0,0 +1,9 @@ +NOTE: Don't expect any of these programs to work with current +OpenSSL releases, or even with later SSLeay releases. + +Original README: +============================================================================= + +Some demo programs sent to me by various people + +eric diff --git a/demos/asn1/README.ASN1 b/demos/asn1/README.ASN1 new file mode 100644 index 0000000..ac497be --- /dev/null +++ b/demos/asn1/README.ASN1 @@ -0,0 +1,7 @@ +This is a demo of the new ASN1 code. Its an OCSP ASN1 module. Doesn't +do much yet other than demonstrate what the new ASN1 modules might look +like. + +It wont even compile yet: the new code isn't in place. + + diff --git a/demos/asn1/ocsp.c b/demos/asn1/ocsp.c new file mode 100644 index 0000000..e89f1f7 --- /dev/null +++ b/demos/asn1/ocsp.c @@ -0,0 +1,366 @@ +/* ocsp.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#include +#include +#include + + + + +/* Example of new ASN1 code, OCSP request + + OCSPRequest ::= SEQUENCE { + tbsRequest TBSRequest, + optionalSignature [0] EXPLICIT Signature OPTIONAL } + + TBSRequest ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + requestorName [1] EXPLICIT GeneralName OPTIONAL, + requestList SEQUENCE OF Request, + requestExtensions [2] EXPLICIT Extensions OPTIONAL } + + Signature ::= SEQUENCE { + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + + Version ::= INTEGER { v1(0) } + + Request ::= SEQUENCE { + reqCert CertID, + singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + + CertID ::= SEQUENCE { + hashAlgorithm AlgorithmIdentifier, + issuerNameHash OCTET STRING, -- Hash of Issuer's DN + issuerKeyHash OCTET STRING, -- Hash of Issuers public key + serialNumber CertificateSerialNumber } + + OCSPResponse ::= SEQUENCE { + responseStatus OCSPResponseStatus, + responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } + + OCSPResponseStatus ::= ENUMERATED { + successful (0), --Response has valid confirmations + malformedRequest (1), --Illegal confirmation request + internalError (2), --Internal error in issuer + tryLater (3), --Try again later + --(4) is not used + sigRequired (5), --Must sign the request + unauthorized (6) --Request unauthorized + } + + ResponseBytes ::= SEQUENCE { + responseType OBJECT IDENTIFIER, + response OCTET STRING } + + BasicOCSPResponse ::= SEQUENCE { + tbsResponseData ResponseData, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + + ResponseData ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + responderID ResponderID, + producedAt GeneralizedTime, + responses SEQUENCE OF SingleResponse, + responseExtensions [1] EXPLICIT Extensions OPTIONAL } + + ResponderID ::= CHOICE { + byName [1] Name, --EXPLICIT + byKey [2] KeyHash } + + KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key + --(excluding the tag and length fields) + + SingleResponse ::= SEQUENCE { + certID CertID, + certStatus CertStatus, + thisUpdate GeneralizedTime, + nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + singleExtensions [1] EXPLICIT Extensions OPTIONAL } + + CertStatus ::= CHOICE { + good [0] IMPLICIT NULL, + revoked [1] IMPLICIT RevokedInfo, + unknown [2] IMPLICIT UnknownInfo } + + RevokedInfo ::= SEQUENCE { + revocationTime GeneralizedTime, + revocationReason [0] EXPLICIT CRLReason OPTIONAL } + + UnknownInfo ::= NULL -- this can be replaced with an enumeration + + ArchiveCutoff ::= GeneralizedTime + + AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER + + ServiceLocator ::= SEQUENCE { + issuer Name, + locator AuthorityInfoAccessSyntax } + + -- Object Identifiers + + id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } + id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp } + id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } + id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 } + id-pkix-ocsp-crl OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 } + id-pkix-ocsp-response OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 } + id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 } + id-pkix-ocsp-archive-cutoff OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 } + id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 } + +*/ + +/* Request Structures */ + +DECLARE_STACK_OF(Request) + +typedef struct { + ASN1_INTEGER *version; + GENERAL_NAME *requestorName; + STACK_OF(Request) *requestList; + STACK_OF(X509_EXTENSION) *requestExtensions; +} TBSRequest; + +typedef struct { + X509_ALGOR *signatureAlgorithm; + ASN1_BIT_STRING *signature; + STACK_OF(X509) *certs; +} Signature; + +typedef struct { + TBSRequest *tbsRequest; + Signature *optionalSignature; +} OCSPRequest; + +typedef struct { + X509_ALGOR *hashAlgorithm; + ASN1_OCTET_STRING *issuerNameHash; + ASN1_OCTET_STRING *issuerKeyHash; + ASN1_INTEGER *certificateSerialNumber; +} CertID; + +typedef struct { + CertID *reqCert; + STACK_OF(X509_EXTENSION) *singleRequestExtensions; +} Request; + +/* Response structures */ + +typedef struct { + ASN1_OBJECT *responseType; + ASN1_OCTET_STRING *response; +} ResponseBytes; + +typedef struct { + ASN1_ENUMERATED *responseStatus; + ResponseBytes *responseBytes; +} OCSPResponse; + +typedef struct { + int type; + union { + X509_NAME *byName; + ASN1_OCTET_STRING *byKey; + }d; +} ResponderID; + +typedef struct { + ASN1_INTEGER *version; + ResponderID *responderID; + ASN1_GENERALIZEDTIME *producedAt; + STACK_OF(SingleResponse) *responses; + STACK_OF(X509_EXTENSION) *responseExtensions; +} ResponseData; + +typedef struct { + ResponseData *tbsResponseData; + X509_ALGOR *signatureAlgorithm; + ASN1_BIT_STRING *signature; + STACK_OF(X509) *certs; +} BasicOCSPResponse; + +typedef struct { + ASN1_GENERALIZEDTIME *revocationTime; + ASN1_ENUMERATED * revocationReason; +} RevokedInfo; + +typedef struct { + int type; + union { + ASN1_NULL *good; + RevokedInfo *revoked; + ASN1_NULL *unknown; + } d; +} CertStatus; + +typedef struct { + CertID *certID; + CertStatus *certStatus; + ASN1_GENERALIZEDTIME *thisUpdate; + ASN1_GENERALIZEDTIME *nextUpdate; + STACK_OF(X509_EXTENSION) *singleExtensions; +} SingleResponse; + + +typedef struct { + X509_NAME *issuer; + STACK_OF(ACCESS_DESCRIPTION) *locator; +} ServiceLocator; + + +/* Now the ASN1 templates */ + +IMPLEMENT_COMPAT_ASN1(X509); +IMPLEMENT_COMPAT_ASN1(X509_ALGOR); +//IMPLEMENT_COMPAT_ASN1(X509_EXTENSION); +IMPLEMENT_COMPAT_ASN1(GENERAL_NAME); +IMPLEMENT_COMPAT_ASN1(X509_NAME); + +ASN1_SEQUENCE(X509_EXTENSION) = { + ASN1_SIMPLE(X509_EXTENSION, object, ASN1_OBJECT), + ASN1_OPT(X509_EXTENSION, critical, ASN1_BOOLEAN), + ASN1_SIMPLE(X509_EXTENSION, value, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(X509_EXTENSION); + + +ASN1_SEQUENCE(Signature) = { + ASN1_SIMPLE(Signature, signatureAlgorithm, X509_ALGOR), + ASN1_SIMPLE(Signature, signature, ASN1_BIT_STRING), + ASN1_SEQUENCE_OF(Signature, certs, X509) +} ASN1_SEQUENCE_END(Signature); + +ASN1_SEQUENCE(CertID) = { + ASN1_SIMPLE(CertID, hashAlgorithm, X509_ALGOR), + ASN1_SIMPLE(CertID, issuerNameHash, ASN1_OCTET_STRING), + ASN1_SIMPLE(CertID, issuerKeyHash, ASN1_OCTET_STRING), + ASN1_SIMPLE(CertID, certificateSerialNumber, ASN1_INTEGER) +} ASN1_SEQUENCE_END(CertID); + +ASN1_SEQUENCE(Request) = { + ASN1_SIMPLE(Request, reqCert, CertID), + ASN1_EXP_SEQUENCE_OF_OPT(Request, singleRequestExtensions, X509_EXTENSION, 0) +} ASN1_SEQUENCE_END(Request); + +ASN1_SEQUENCE(TBSRequest) = { + ASN1_EXP_OPT(TBSRequest, version, ASN1_INTEGER, 0), + ASN1_EXP_OPT(TBSRequest, requestorName, GENERAL_NAME, 1), + ASN1_SEQUENCE_OF(TBSRequest, requestList, Request), + ASN1_EXP_SEQUENCE_OF_OPT(TBSRequest, requestExtensions, X509_EXTENSION, 2) +} ASN1_SEQUENCE_END(TBSRequest); + +ASN1_SEQUENCE(OCSPRequest) = { + ASN1_SIMPLE(OCSPRequest, tbsRequest, TBSRequest), + ASN1_EXP_OPT(OCSPRequest, optionalSignature, Signature, 0) +} ASN1_SEQUENCE_END(OCSPRequest); + + +/* Response templates */ + +ASN1_SEQUENCE(ResponseBytes) = { + ASN1_SIMPLE(ResponseBytes, responseType, ASN1_OBJECT), + ASN1_SIMPLE(ResponseBytes, response, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(ResponseBytes); + +ASN1_SEQUENCE(OCSPResponse) = { + ASN1_SIMPLE(OCSPResponse, responseStatus, ASN1_ENUMERATED), + ASN1_EXP_OPT(OCSPResponse, responseBytes, ResponseBytes, 0) +} ASN1_SEQUENCE_END(OCSPResponse); + +ASN1_CHOICE(ResponderID) = { + ASN1_EXP(ResponderID, d.byName, X509_NAME, 1), + ASN1_IMP(ResponderID, d.byKey, ASN1_OCTET_STRING, 2) +} ASN1_CHOICE_END(ResponderID); + +ASN1_SEQUENCE(RevokedInfo) = { + ASN1_SIMPLE(RevokedInfo, revocationTime, ASN1_GENERALIZEDTIME), + ASN1_EXP_OPT(RevokedInfo, revocationReason, ASN1_ENUMERATED, 0) +} ASN1_SEQUENCE_END(RevokedInfo); + +ASN1_CHOICE(CertStatus) = { + ASN1_IMP(CertStatus, d.good, ASN1_NULL, 0), + ASN1_IMP(CertStatus, d.revoked, RevokedInfo, 1), + ASN1_IMP(CertStatus, d.unknown, ASN1_NULL, 2) +} ASN1_CHOICE_END(CertStatus); + +ASN1_SEQUENCE(SingleResponse) = { + ASN1_SIMPLE(SingleResponse, certID, CertID), + ASN1_SIMPLE(SingleResponse, certStatus, CertStatus), + ASN1_SIMPLE(SingleResponse, thisUpdate, ASN1_GENERALIZEDTIME), + ASN1_EXP_OPT(SingleResponse, nextUpdate, ASN1_GENERALIZEDTIME, 0), + ASN1_EXP_SEQUENCE_OF_OPT(SingleResponse, singleExtensions, X509_EXTENSION, 1) +} ASN1_SEQUENCE_END(SingleResponse); + +ASN1_SEQUENCE(ResponseData) = { + ASN1_EXP_OPT(ResponseData, version, ASN1_INTEGER, 0), + ASN1_SIMPLE(ResponseData, responderID, ResponderID), + ASN1_SIMPLE(ResponseData, producedAt, ASN1_GENERALIZEDTIME), + ASN1_SEQUENCE_OF(ResponseData, responses, SingleResponse), + ASN1_EXP_SEQUENCE_OF_OPT(ResponseData, responseExtensions, X509_EXTENSION, 1) +} ASN1_SEQUENCE_END(ResponseData); + +ASN1_SEQUENCE(BasicOCSPResponse) = { + ASN1_SIMPLE(BasicOCSPResponse, tbsResponseData, ResponseData), + ASN1_SIMPLE(BasicOCSPResponse, signatureAlgorithm, X509_ALGOR), + ASN1_SIMPLE(BasicOCSPResponse, signature, ASN1_BIT_STRING), + ASN1_EXP_SEQUENCE_OF_OPT(BasicOCSPResponse, certs, X509, 0) +} ASN1_SEQUENCE_END(BasicOCSPResponse); + diff --git a/demos/b64.c b/demos/b64.c new file mode 100644 index 0000000..efdd444 --- /dev/null +++ b/demos/b64.c @@ -0,0 +1,268 @@ +/* demos/b64.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include +#include "../apps/apps.h" +#include +#include +#include +#include +#include +#include + +#undef SIZE +#undef BSIZE +#undef PROG + +#define SIZE (512) +#define BSIZE (8*1024) +#define PROG enc_main + +int main(argc,argv) +int argc; +char **argv; + { + char *strbuf=NULL; + unsigned char *buff=NULL,*bufsize=NULL; + int bsize=BSIZE,verbose=0; + int ret=1,inl; + char *str=NULL; + char *hkey=NULL,*hiv=NULL; + int enc=1,printkey=0,i,base64=0; + int debug=0; + EVP_CIPHER *cipher=NULL,*c; + char *inf=NULL,*outf=NULL; + BIO *in=NULL,*out=NULL,*b64=NULL,*benc=NULL,*rbio=NULL,*wbio=NULL; +#define PROG_NAME_SIZE 39 + + + apps_startup(); + + if (bio_err == NULL) + if ((bio_err=BIO_new(BIO_s_file())) != NULL) + BIO_set_fp(bio_err,stderr,BIO_NOCLOSE); + + base64=1; + + argc--; + argv++; + while (argc >= 1) + { + if (strcmp(*argv,"-e") == 0) + enc=1; + if (strcmp(*argv,"-in") == 0) + { + if (--argc < 1) goto bad; + inf= *(++argv); + } + else if (strcmp(*argv,"-out") == 0) + { + if (--argc < 1) goto bad; + outf= *(++argv); + } + else if (strcmp(*argv,"-d") == 0) + enc=0; + else if (strcmp(*argv,"-v") == 0) + verbose=1; + else if (strcmp(*argv,"-debug") == 0) + debug=1; + else if (strcmp(*argv,"-bufsize") == 0) + { + if (--argc < 1) goto bad; + bufsize=(unsigned char *)*(++argv); + } + else + { + BIO_printf(bio_err,"unknown option '%s'\n",*argv); +bad: + BIO_printf(bio_err,"options are\n"); + BIO_printf(bio_err,"%-14s input file\n","-in "); + BIO_printf(bio_err,"%-14s output file\n","-out "); + BIO_printf(bio_err,"%-14s encode\n","-e"); + BIO_printf(bio_err,"%-14s decode\n","-d"); + BIO_printf(bio_err,"%-14s buffer size\n","-bufsize "); + + goto end; + } + argc--; + argv++; + } + + if (bufsize != NULL) + { + int i; + unsigned long n; + + for (n=0; *bufsize; bufsize++) + { + i= *bufsize; + if ((i <= '9') && (i >= '0')) + n=n*10+i-'0'; + else if (i == 'k') + { + n*=1024; + bufsize++; + break; + } + } + if (*bufsize != '\0') + { + BIO_printf(bio_err,"invalid 'bufsize' specified.\n"); + goto end; + } + + /* It must be large enough for a base64 encoded line */ + if (n < 80) n=80; + + bsize=(int)n; + if (verbose) BIO_printf(bio_err,"bufsize=%d\n",bsize); + } + + strbuf=OPENSSL_malloc(SIZE); + buff=(unsigned char *)OPENSSL_malloc(EVP_ENCODE_LENGTH(bsize)); + if ((buff == NULL) || (strbuf == NULL)) + { + BIO_printf(bio_err,"OPENSSL_malloc failure\n"); + goto end; + } + + in=BIO_new(BIO_s_file()); + out=BIO_new(BIO_s_file()); + if ((in == NULL) || (out == NULL)) + { + ERR_print_errors(bio_err); + goto end; + } + if (debug) + { + BIO_set_callback(in,BIO_debug_callback); + BIO_set_callback(out,BIO_debug_callback); + BIO_set_callback_arg(in,bio_err); + BIO_set_callback_arg(out,bio_err); + } + + if (inf == NULL) + BIO_set_fp(in,stdin,BIO_NOCLOSE); + else + { + if (BIO_read_filename(in,inf) <= 0) + { + perror(inf); + goto end; + } + } + + if (outf == NULL) + BIO_set_fp(out,stdout,BIO_NOCLOSE); + else + { + if (BIO_write_filename(out,outf) <= 0) + { + perror(outf); + goto end; + } + } + + rbio=in; + wbio=out; + + if (base64) + { + if ((b64=BIO_new(BIO_f_base64())) == NULL) + goto end; + if (debug) + { + BIO_set_callback(b64,BIO_debug_callback); + BIO_set_callback_arg(b64,bio_err); + } + if (enc) + wbio=BIO_push(b64,wbio); + else + rbio=BIO_push(b64,rbio); + } + + for (;;) + { + inl=BIO_read(rbio,(char *)buff,bsize); + if (inl <= 0) break; + if (BIO_write(wbio,(char *)buff,inl) != inl) + { + BIO_printf(bio_err,"error writing output file\n"); + goto end; + } + } + BIO_flush(wbio); + + ret=0; + if (verbose) + { + BIO_printf(bio_err,"bytes read :%8ld\n",BIO_number_read(in)); + BIO_printf(bio_err,"bytes written:%8ld\n",BIO_number_written(out)); + } +end: + if (strbuf != NULL) OPENSSL_free(strbuf); + if (buff != NULL) OPENSSL_free(buff); + if (in != NULL) BIO_free(in); + if (out != NULL) BIO_free(out); + if (benc != NULL) BIO_free(benc); + if (b64 != NULL) BIO_free(b64); + EXIT(ret); + } + diff --git a/demos/b64.pl b/demos/b64.pl new file mode 100644 index 0000000..8aa5fb4 --- /dev/null +++ b/demos/b64.pl @@ -0,0 +1,20 @@ +#!/usr/local/bin/perl + +# +# Make PEM encoded data have lines of 64 bytes of data +# + +while (<>) + { + if (/^-----BEGIN/ .. /^-----END/) + { + if (/^-----BEGIN/) { $first=$_; next; } + if (/^-----END/) { $last=$_; next; } + $out.=$_; + } + } +$out =~ s/\s//g; +$out =~ s/(.{64})/$1\n/g; +print "$first$out\n$last\n"; + + diff --git a/demos/bio/Makefile b/demos/bio/Makefile new file mode 100644 index 0000000..4351540 --- /dev/null +++ b/demos/bio/Makefile @@ -0,0 +1,16 @@ +CC=cc +CFLAGS= -g -I../../include +LIBS= -L../.. ../../libssl.a ../../libcrypto.a +EXAMPLES=saccept sconnect + +all: $(EXAMPLES) + +saccept: saccept.o + $(CC) -o saccept saccept.o $(LIBS) + +sconnect: sconnect.o + $(CC) -o sconnect sconnect.o $(LIBS) + +clean: + rm -f $(EXAMPLES) *.o + diff --git a/demos/bio/README b/demos/bio/README new file mode 100644 index 0000000..0b24e5b --- /dev/null +++ b/demos/bio/README @@ -0,0 +1,3 @@ +This directory contains some simple examples of the use of BIO's +to simplify socket programming. + diff --git a/demos/bio/saccept.c b/demos/bio/saccept.c new file mode 100644 index 0000000..40cd4da --- /dev/null +++ b/demos/bio/saccept.c @@ -0,0 +1,112 @@ +/* NOCW */ +/* demos/bio/saccept.c */ + +/* A minimal program to server an SSL connection. + * It uses blocking. + * saccept host:port + * host is the interface IP to use. If any interface, use *:port + * The default it *:4433 + * + * cc -I../../include saccept.c -L../.. -lssl -lcrypto + */ + +#include +#include +#include +#include + +#define CERT_FILE "server.pem" + +BIO *in=NULL; + +void close_up() + { + if (in != NULL) + BIO_free(in); + } + +int main(argc,argv) +int argc; +char *argv[]; + { + char *port=NULL; + BIO *ssl_bio,*tmp; + SSL_CTX *ctx; + SSL *ssl; + char buf[512]; + int ret=1,i; + + if (argc <= 1) + port="*:4433"; + else + port=argv[1]; + + signal(SIGINT,close_up); + + SSL_load_error_strings(); + +#ifdef WATT32 + dbug_init(); + sock_init(); +#endif + + /* Add ciphers and message digests */ + OpenSSL_add_ssl_algorithms(); + + ctx=SSL_CTX_new(SSLv23_server_method()); + if (!SSL_CTX_use_certificate_file(ctx,CERT_FILE,SSL_FILETYPE_PEM)) + goto err; + if (!SSL_CTX_use_PrivateKey_file(ctx,CERT_FILE,SSL_FILETYPE_PEM)) + goto err; + if (!SSL_CTX_check_private_key(ctx)) + goto err; + + /* Setup server side SSL bio */ + ssl=SSL_new(ctx); + ssl_bio=BIO_new_ssl(ctx,0); + + if ((in=BIO_new_accept(port)) == NULL) goto err; + + /* This means that when a new connection is acceptede on 'in', + * The ssl_bio will be 'dupilcated' and have the new socket + * BIO push into it. Basically it means the SSL BIO will be + * automatically setup */ + BIO_set_accept_bios(in,ssl_bio); + +again: + /* The first call will setup the accept socket, and the second + * will get a socket. In this loop, the first actual accept + * will occur in the BIO_read() function. */ + + if (BIO_do_accept(in) <= 0) goto err; + + for (;;) + { + i=BIO_read(in,buf,512); + if (i == 0) + { + /* If we have finished, remove the underlying + * BIO stack so the next time we call any function + * for this BIO, it will attempt to do an + * accept */ + printf("Done\n"); + tmp=BIO_pop(in); + BIO_free_all(tmp); + goto again; + } + if (i < 0) goto err; + fwrite(buf,1,i,stdout); + fflush(stdout); + } + + ret=0; +err: + if (ret) + { + ERR_print_errors_fp(stderr); + } + if (in != NULL) BIO_free(in); + exit(ret); + return(!ret); + } + diff --git a/demos/bio/sconnect.c b/demos/bio/sconnect.c new file mode 100644 index 0000000..880344e --- /dev/null +++ b/demos/bio/sconnect.c @@ -0,0 +1,121 @@ +/* NOCW */ +/* demos/bio/sconnect.c */ + +/* A minimal program to do SSL to a passed host and port. + * It is actually using non-blocking IO but in a very simple manner + * sconnect host:port - it does a 'GET / HTTP/1.0' + * + * cc -I../../include sconnect.c -L../.. -lssl -lcrypto + */ +#include +#include +#include +#include +#include + +extern int errno; + +int main(argc,argv) +int argc; +char *argv[]; + { + char *host; + BIO *out; + char buf[1024*10],*p; + SSL_CTX *ssl_ctx=NULL; + SSL *ssl; + BIO *ssl_bio; + int i,len,off,ret=1; + + if (argc <= 1) + host="localhost:4433"; + else + host=argv[1]; + +#ifdef WATT32 + dbug_init(); + sock_init(); +#endif + + /* Lets get nice error messages */ + SSL_load_error_strings(); + + /* Setup all the global SSL stuff */ + OpenSSL_add_ssl_algorithms(); + ssl_ctx=SSL_CTX_new(SSLv23_client_method()); + + /* Lets make a SSL structure */ + ssl=SSL_new(ssl_ctx); + SSL_set_connect_state(ssl); + + /* Use it inside an SSL BIO */ + ssl_bio=BIO_new(BIO_f_ssl()); + BIO_set_ssl(ssl_bio,ssl,BIO_CLOSE); + + /* Lets use a connect BIO under the SSL BIO */ + out=BIO_new(BIO_s_connect()); + BIO_set_conn_hostname(out,host); + BIO_set_nbio(out,1); + out=BIO_push(ssl_bio,out); + + p="GET / HTTP/1.0\r\n\r\n"; + len=strlen(p); + + off=0; + for (;;) + { + i=BIO_write(out,&(p[off]),len); + if (i <= 0) + { + if (BIO_should_retry(out)) + { + fprintf(stderr,"write DELAY\n"); + sleep(1); + continue; + } + else + { + goto err; + } + } + off+=i; + len-=i; + if (len <= 0) break; + } + + for (;;) + { + i=BIO_read(out,buf,sizeof(buf)); + if (i == 0) break; + if (i < 0) + { + if (BIO_should_retry(out)) + { + fprintf(stderr,"read DELAY\n"); + sleep(1); + continue; + } + goto err; + } + fwrite(buf,1,i,stdout); + } + + ret=1; + + if (0) + { +err: + if (ERR_peek_error() == 0) /* system call error */ + { + fprintf(stderr,"errno=%d ",errno); + perror("error"); + } + else + ERR_print_errors_fp(stderr); + } + BIO_free_all(out); + if (ssl_ctx != NULL) SSL_CTX_free(ssl_ctx); + exit(!ret); + return(ret); + } + diff --git a/demos/bio/server.pem b/demos/bio/server.pem new file mode 100644 index 0000000..5cf1387 --- /dev/null +++ b/demos/bio/server.pem @@ -0,0 +1,30 @@ +subject=/C=AU/SP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server +issuer= /C=AU/SP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA +-----BEGIN X509 CERTIFICATE----- + +MIIBgjCCASwCAQQwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV +BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MTAwOTIz +MzIwNVoXDTk4MDcwNTIzMzIwNVowYDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM +RDEZMBcGA1UEChMQTWluY29tIFB0eS4gTHRkLjELMAkGA1UECxMCQ1MxGzAZBgNV +BAMTElNTTGVheSBkZW1vIHNlcnZlcjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3 +LCXcScWua0PFLkHBLm2VejqpA1F4RQ8q0VjRiPafjx/Z/aWH3ipdMVvuJGa/wFXb +/nDFLDlfWp+oCPwhBtVPAgMBAAEwDQYJKoZIhvcNAQEEBQADQQArNFsihWIjBzb0 +DCsU0BvL2bvSwJrPEqFlkDq3F4M6EGutL9axEcANWgbbEdAvNJD1dmEmoWny27Pn +IMs6ZOZB +-----END X509 CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- + +MIIBPAIBAAJBALcsJdxJxa5rQ8UuQcEubZV6OqkDUXhFDyrRWNGI9p+PH9n9pYfe +Kl0xW+4kZr/AVdv+cMUsOV9an6gI/CEG1U8CAwEAAQJAXJMBZ34ZXHd1vtgL/3hZ +hexKbVTx/djZO4imXO/dxPGRzG2ylYZpHmG32/T1kaHpZlCHoEPgHoSzmxYXfxjG +sQIhAPmZ/bQOjmRUHM/VM2X5zrjjM6z18R1P6l3ObFwt9FGdAiEAu943Yh9SqMRw +tL0xHGxKmM/YJueUw1gB6sLkETN71NsCIQCeT3RhoqXfrpXDoEcEU+gwzjI1bpxq +agiNTOLfqGoA5QIhAIQFYjgzONxex7FLrsKBm16N2SFl5pXsN9SpRqqL2n63AiEA +g9VNIQ3xwpw7og3IbONifeku+J9qGMGQJMKwSTwrFtI= +-----END RSA PRIVATE KEY----- + +-----BEGIN DH PARAMETERS----- +MEYCQQDaWDwW2YUiidDkr3VvTMqS3UvlM7gE+w/tlO+cikQD7VdGUNNpmdsp13Yn +a6LT1BLiGPTdHghM9tgAPnxHdOgzAgEC +-----END DH PARAMETERS----- + diff --git a/demos/cms/cacert.pem b/demos/cms/cacert.pem new file mode 100644 index 0000000..75cbb34 --- /dev/null +++ b/demos/cms/cacert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6DCCAlGgAwIBAgIJAMfGO3rdo2uUMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV +BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv +dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTc0MzE3 +WhcNMTcwNDEwMTc0MzE3WjBXMQswCQYDVQQGEwJVSzESMBAGA1UEBxMJVGVzdCBD +aXR5MRYwFAYDVQQKEw1PcGVuU1NMIEdyb3VwMRwwGgYDVQQDExNUZXN0IFMvTUlN +RSBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqJMal1uC1/1wz +i5+dE4EZF2im3BgROm5PVMbwPY9V1t+KYvtdc3rMcRgJaMbP+qaEcDXoIsZfYXGR +ielgfDNZmZcj1y/FOum+Jc2OZMs3ggPmjIQ3dbBECq0hZKcbz7wfr+2OeNWm46iT +jcSIXpGIRhUYEzOgv7zb8oOU70IbbwIDAQABo4G7MIG4MB0GA1UdDgQWBBRHUypx +CXFQYqewhGo72lWPQUsjoDCBiAYDVR0jBIGAMH6AFEdTKnEJcVBip7CEajvaVY9B +SyOgoVukWTBXMQswCQYDVQQGEwJVSzESMBAGA1UEBxMJVGVzdCBDaXR5MRYwFAYD +VQQKEw1PcGVuU1NMIEdyb3VwMRwwGgYDVQQDExNUZXN0IFMvTUlNRSBSb290IENB +ggkAx8Y7et2ja5QwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQANI+Yc +G/YDM1WMUGEzEkU9UhsIUqdyBebnK3+OyxZSouDcE/M10jFJzBf/F5b0uUGAKWwo +u0dzmILfKjdfWe8EyCRafZcm00rVcO09i/63FBYzlHbmfUATIqZdhKzxxQMPs5mF +1je+pHUpzIY8TSXyh/uD9IkAy04IHwGZQf9akw== +-----END CERTIFICATE----- diff --git a/demos/cms/cakey.pem b/demos/cms/cakey.pem new file mode 100644 index 0000000..3b53c5e --- /dev/null +++ b/demos/cms/cakey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQCqJMal1uC1/1wzi5+dE4EZF2im3BgROm5PVMbwPY9V1t+KYvtd +c3rMcRgJaMbP+qaEcDXoIsZfYXGRielgfDNZmZcj1y/FOum+Jc2OZMs3ggPmjIQ3 +dbBECq0hZKcbz7wfr+2OeNWm46iTjcSIXpGIRhUYEzOgv7zb8oOU70IbbwIDAQAB +AoGBAKWOZ2UTc1BkjDjz0XoscmAR8Rj77MdGzfOPkIxPultSW+3yZpkGNyUbnsH5 +HAtf4Avai/m3bMN+s91kDpx9/g/I9ZEHPQLcDICETvwt/EHT7+hwvaQgsM+TgpMs +tjlGZOWent6wVIuvwwzqOMXZLgK9FvY7upwgtrys4G3Kab5hAkEA2QzFflWyEvKS +rMSaVtn/IjFilwa7H0IdakkjM34z4peerFTPBr4J47YD4RCR/dAvxyNy3zUxtH18 +9R6dUixI6QJBAMitJD0xOkbGWBX8KVJvRiKOIdf/95ZUAgN/h3bWKy57EB9NYj3u +jbxXcvdjfSqiITykkjAg7SG7nrlzJsu6CpcCQG6gVsy0auXDY0TRlASuaZ6I40Is +uRUOgqWYj2uAaHuWYdZeB4LdO3cnX0TISFDAWom6JKNlnmbrCtR4fSDT13kCQQCU ++VQJyV3F5MDHsWbLt6eNR46AV5lpk/vatPXPlrZ/zwPs+PmRmGLICvNiDA2DdNDP +wCx2Zjsj67CtY3rNitMJAkEAm09BQnjnbBXUb1rd2SjNDWTsu80Z+zLu8pAwXNhW +8nsvMYqlYMIxuMPwu/QuTnMRhMZ08uhqoD3ukZnBeoMEVg== +-----END RSA PRIVATE KEY----- diff --git a/demos/cms/cms_comp.c b/demos/cms/cms_comp.c new file mode 100644 index 0000000..b7943e8 --- /dev/null +++ b/demos/cms/cms_comp.c @@ -0,0 +1,61 @@ +/* Simple S/MIME compress example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL; + CMS_ContentInfo *cms = NULL; + int ret = 1; + + /* + * On OpenSSL 0.9.9 only: + * for streaming set CMS_STREAM + */ + int flags = CMS_STREAM; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Open content being compressed */ + + in = BIO_new_file("comp.txt", "r"); + + if (!in) + goto err; + + /* compress content */ + cms = CMS_compress(in, NID_zlib_compression, flags); + + if (!cms) + goto err; + + out = BIO_new_file("smcomp.txt", "w"); + if (!out) + goto err; + + /* Write out S/MIME message */ + if (!SMIME_write_CMS(out, cms, in, flags)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Compressing Data\n"); + ERR_print_errors_fp(stderr); + } + + if (cms) + CMS_ContentInfo_free(cms); + if (in) + BIO_free(in); + if (out) + BIO_free(out); + + return ret; + + } diff --git a/demos/cms/cms_ddec.c b/demos/cms/cms_ddec.c new file mode 100644 index 0000000..ba68cfd --- /dev/null +++ b/demos/cms/cms_ddec.c @@ -0,0 +1,89 @@ +/* S/MIME detached data decrypt example: rarely done but + * should the need arise this is an example.... + */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL, *dcont = NULL; + X509 *rcert = NULL; + EVP_PKEY *rkey = NULL; + CMS_ContentInfo *cms = NULL; + int ret = 1; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Read in recipient certificate and private key */ + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + BIO_reset(tbio); + + rkey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); + + if (!rcert || !rkey) + goto err; + + /* Open PEM file containing enveloped data */ + + in = BIO_new_file("smencr.pem", "r"); + + if (!in) + goto err; + + /* Parse PEM content */ + cms = PEM_read_bio_CMS(in, NULL, 0, NULL); + + if (!cms) + goto err; + + /* Open file containing detached content */ + dcont = BIO_new_file("smencr.out", "rb"); + + if (!in) + goto err; + + out = BIO_new_file("encrout.txt", "w"); + if (!out) + goto err; + + /* Decrypt S/MIME message */ + if (!CMS_decrypt(cms, rkey, rcert, dcont, out, 0)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Decrypting Data\n"); + ERR_print_errors_fp(stderr); + } + + if (cms) + CMS_ContentInfo_free(cms); + if (rcert) + X509_free(rcert); + if (rkey) + EVP_PKEY_free(rkey); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + if (dcont) + BIO_free(dcont); + + return ret; + + } diff --git a/demos/cms/cms_dec.c b/demos/cms/cms_dec.c new file mode 100644 index 0000000..7ddf653 --- /dev/null +++ b/demos/cms/cms_dec.c @@ -0,0 +1,79 @@ +/* Simple S/MIME decryption example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL; + X509 *rcert = NULL; + EVP_PKEY *rkey = NULL; + CMS_ContentInfo *cms = NULL; + int ret = 1; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Read in recipient certificate and private key */ + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + BIO_reset(tbio); + + rkey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); + + if (!rcert || !rkey) + goto err; + + /* Open S/MIME message to decrypt */ + + in = BIO_new_file("smencr.txt", "r"); + + if (!in) + goto err; + + /* Parse message */ + cms = SMIME_read_CMS(in, NULL); + + if (!cms) + goto err; + + out = BIO_new_file("decout.txt", "w"); + if (!out) + goto err; + + /* Decrypt S/MIME message */ + if (!CMS_decrypt(cms, rkey, rcert, out, NULL, 0)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Decrypting Data\n"); + ERR_print_errors_fp(stderr); + } + + if (cms) + CMS_ContentInfo_free(cms); + if (rcert) + X509_free(rcert); + if (rkey) + EVP_PKEY_free(rkey); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } diff --git a/demos/cms/cms_denc.c b/demos/cms/cms_denc.c new file mode 100644 index 0000000..9265e47 --- /dev/null +++ b/demos/cms/cms_denc.c @@ -0,0 +1,97 @@ +/* S/MIME detached data encrypt example: rarely done but + * should the need arise this is an example.... + */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL, *dout = NULL; + X509 *rcert = NULL; + STACK_OF(X509) *recips = NULL; + CMS_ContentInfo *cms = NULL; + int ret = 1; + + int flags = CMS_STREAM|CMS_DETACHED; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Read in recipient certificate */ + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + if (!rcert) + goto err; + + /* Create recipient STACK and add recipient cert to it */ + recips = sk_X509_new_null(); + + if (!recips || !sk_X509_push(recips, rcert)) + goto err; + + /* sk_X509_pop_free will free up recipient STACK and its contents + * so set rcert to NULL so it isn't freed up twice. + */ + rcert = NULL; + + /* Open content being encrypted */ + + in = BIO_new_file("encr.txt", "r"); + + dout = BIO_new_file("smencr.out", "wb"); + + if (!in) + goto err; + + /* encrypt content */ + cms = CMS_encrypt(recips, in, EVP_des_ede3_cbc(), flags); + + if (!cms) + goto err; + + out = BIO_new_file("smencr.pem", "w"); + if (!out) + goto err; + + if (!CMS_final(cms, in, dout, flags)) + goto err; + + /* Write out CMS structure without content */ + if (!PEM_write_bio_CMS(out, cms)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Encrypting Data\n"); + ERR_print_errors_fp(stderr); + } + + if (cms) + CMS_ContentInfo_free(cms); + if (rcert) + X509_free(rcert); + if (recips) + sk_X509_pop_free(recips, X509_free); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (dout) + BIO_free(dout); + if (tbio) + BIO_free(tbio); + + return ret; + + } diff --git a/demos/cms/cms_enc.c b/demos/cms/cms_enc.c new file mode 100644 index 0000000..916b479 --- /dev/null +++ b/demos/cms/cms_enc.c @@ -0,0 +1,92 @@ +/* Simple S/MIME encrypt example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL; + X509 *rcert = NULL; + STACK_OF(X509) *recips = NULL; + CMS_ContentInfo *cms = NULL; + int ret = 1; + + /* + * On OpenSSL 1.0.0 and later only: + * for streaming set CMS_STREAM + */ + int flags = CMS_STREAM; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Read in recipient certificate */ + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + if (!rcert) + goto err; + + /* Create recipient STACK and add recipient cert to it */ + recips = sk_X509_new_null(); + + if (!recips || !sk_X509_push(recips, rcert)) + goto err; + + /* sk_X509_pop_free will free up recipient STACK and its contents + * so set rcert to NULL so it isn't freed up twice. + */ + rcert = NULL; + + /* Open content being encrypted */ + + in = BIO_new_file("encr.txt", "r"); + + if (!in) + goto err; + + /* encrypt content */ + cms = CMS_encrypt(recips, in, EVP_des_ede3_cbc(), flags); + + if (!cms) + goto err; + + out = BIO_new_file("smencr.txt", "w"); + if (!out) + goto err; + + /* Write out S/MIME message */ + if (!SMIME_write_CMS(out, cms, in, flags)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Encrypting Data\n"); + ERR_print_errors_fp(stderr); + } + + if (cms) + CMS_ContentInfo_free(cms); + if (rcert) + X509_free(rcert); + if (recips) + sk_X509_pop_free(recips, X509_free); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } diff --git a/demos/cms/cms_sign.c b/demos/cms/cms_sign.c new file mode 100644 index 0000000..42f7620 --- /dev/null +++ b/demos/cms/cms_sign.c @@ -0,0 +1,89 @@ +/* Simple S/MIME signing example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL; + X509 *scert = NULL; + EVP_PKEY *skey = NULL; + CMS_ContentInfo *cms = NULL; + int ret = 1; + + /* For simple S/MIME signing use CMS_DETACHED. + * On OpenSSL 0.9.9 only: + * for streaming detached set CMS_DETACHED|CMS_STREAM + * for streaming non-detached set CMS_STREAM + */ + int flags = CMS_DETACHED|CMS_STREAM; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Read in signer certificate and private key */ + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + scert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + BIO_reset(tbio); + + skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); + + if (!scert || !skey) + goto err; + + /* Open content being signed */ + + in = BIO_new_file("sign.txt", "r"); + + if (!in) + goto err; + + /* Sign content */ + cms = CMS_sign(scert, skey, NULL, in, flags); + + if (!cms) + goto err; + + out = BIO_new_file("smout.txt", "w"); + if (!out) + goto err; + + if (!(flags & CMS_STREAM)) + BIO_reset(in); + + /* Write out S/MIME message */ + if (!SMIME_write_CMS(out, cms, in, flags)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Signing Data\n"); + ERR_print_errors_fp(stderr); + } + + if (cms) + CMS_ContentInfo_free(cms); + if (scert) + X509_free(scert); + if (skey) + EVP_PKEY_free(skey); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } diff --git a/demos/cms/cms_sign2.c b/demos/cms/cms_sign2.c new file mode 100644 index 0000000..36adee7 --- /dev/null +++ b/demos/cms/cms_sign2.c @@ -0,0 +1,103 @@ +/* S/MIME signing example: 2 signers */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL; + X509 *scert = NULL, *scert2 = NULL; + EVP_PKEY *skey = NULL, *skey2 = NULL; + CMS_ContentInfo *cms = NULL; + int ret = 1; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + scert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + BIO_reset(tbio); + + skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); + + BIO_free(tbio); + + tbio = BIO_new_file("signer2.pem", "r"); + + if (!tbio) + goto err; + + scert2 = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + BIO_reset(tbio); + + skey2 = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); + + if (!scert2 || !skey2) + goto err; + + in = BIO_new_file("sign.txt", "r"); + + if (!in) + goto err; + + cms = CMS_sign(NULL, NULL, NULL, in, CMS_STREAM|CMS_PARTIAL); + + if (!cms) + goto err; + + /* Add each signer in turn */ + + if (!CMS_add1_signer(cms, scert, skey, NULL, 0)) + goto err; + + if (!CMS_add1_signer(cms, scert2, skey2, NULL, 0)) + goto err; + + out = BIO_new_file("smout.txt", "w"); + if (!out) + goto err; + + /* NB: content included and finalized by SMIME_write_CMS */ + + if (!SMIME_write_CMS(out, cms, in, CMS_STREAM)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Signing Data\n"); + ERR_print_errors_fp(stderr); + } + + if (cms) + CMS_ContentInfo_free(cms); + + if (scert) + X509_free(scert); + if (skey) + EVP_PKEY_free(skey); + + if (scert2) + X509_free(scert2); + if (skey) + EVP_PKEY_free(skey2); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } diff --git a/demos/cms/cms_uncomp.c b/demos/cms/cms_uncomp.c new file mode 100644 index 0000000..f15ae2f --- /dev/null +++ b/demos/cms/cms_uncomp.c @@ -0,0 +1,56 @@ +/* Simple S/MIME uncompression example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL; + CMS_ContentInfo *cms = NULL; + int ret = 1; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Open compressed content */ + + in = BIO_new_file("smcomp.txt", "r"); + + if (!in) + goto err; + + /* Sign content */ + cms = SMIME_read_CMS(in, NULL); + + if (!cms) + goto err; + + out = BIO_new_file("smuncomp.txt", "w"); + if (!out) + goto err; + + /* Uncompress S/MIME message */ + if (!CMS_uncompress(cms, out, NULL, 0)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Uncompressing Data\n"); + ERR_print_errors_fp(stderr); + } + + if (cms) + CMS_ContentInfo_free(cms); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + + return ret; + + } diff --git a/demos/cms/cms_ver.c b/demos/cms/cms_ver.c new file mode 100644 index 0000000..bf1145e --- /dev/null +++ b/demos/cms/cms_ver.c @@ -0,0 +1,87 @@ +/* Simple S/MIME verification example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL, *cont = NULL; + X509_STORE *st = NULL; + X509 *cacert = NULL; + CMS_ContentInfo *cms = NULL; + + int ret = 1; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Set up trusted CA certificate store */ + + st = X509_STORE_new(); + + /* Read in CA certificate */ + tbio = BIO_new_file("cacert.pem", "r"); + + if (!tbio) + goto err; + + cacert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + if (!cacert) + goto err; + + if (!X509_STORE_add_cert(st, cacert)) + goto err; + + /* Open message being verified */ + + in = BIO_new_file("smout.txt", "r"); + + if (!in) + goto err; + + /* parse message */ + cms = SMIME_read_CMS(in, &cont); + + if (!cms) + goto err; + + /* File to output verified content to */ + out = BIO_new_file("smver.txt", "w"); + if (!out) + goto err; + + if (!CMS_verify(cms, NULL, st, cont, out, 0)) + { + fprintf(stderr, "Verification Failure\n"); + goto err; + } + + fprintf(stderr, "Verification Successful\n"); + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Verifying Data\n"); + ERR_print_errors_fp(stderr); + } + + if (cms) + CMS_ContentInfo_free(cms); + + if (cacert) + X509_free(cacert); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } diff --git a/demos/cms/comp.txt b/demos/cms/comp.txt new file mode 100644 index 0000000..1672328 --- /dev/null +++ b/demos/cms/comp.txt @@ -0,0 +1,22 @@ +Content-type: text/plain + +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed +Some Text To be Compressed diff --git a/demos/cms/encr.txt b/demos/cms/encr.txt new file mode 100644 index 0000000..0eceb40 --- /dev/null +++ b/demos/cms/encr.txt @@ -0,0 +1,3 @@ +Content-type: text/plain + +Sample OpenSSL Data for CMS encryption diff --git a/demos/cms/sign.txt b/demos/cms/sign.txt new file mode 100644 index 0000000..c3f9d73 --- /dev/null +++ b/demos/cms/sign.txt @@ -0,0 +1,3 @@ +Content-type: text/plain + +Test OpenSSL CMS Signed Content diff --git a/demos/cms/signer.pem b/demos/cms/signer.pem new file mode 100644 index 0000000..bac16ba --- /dev/null +++ b/demos/cms/signer.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIICpjCCAg+gAwIBAgIJAJ+rfmEoLQRhMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV +BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv +dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTgyOTI3 +WhcNMTcwNDA5MTgyOTI3WjBWMQswCQYDVQQGEwJVSzElMCMGA1UEAxMcT3BlblNT +TCB0ZXN0IFMvTUlNRSBzaWduZXIgMTEgMB4GCSqGSIb3DQEJARYRdGVzdDFAb3Bl +bnNzbC5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL1ocAQ7ON2pIUXz +jwKPzpPB9ozB6PFG6F6kARO+i0DiT6Qn8abUjwpHPU+lGys83QlpbkQVUD6Fv/4L +ytihk6N9Pr/feECVcSZ20dI43WXjfYak14dSVrZkGNMMXqKmnnqtkAdD0oJN7A7y +gcf8RuViV0kvk9/36eCMwMHrImfhAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI +AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW +BBSyKqjvctIsFNBHULBTqr8SHtSxpDAfBgNVHSMEGDAWgBRHUypxCXFQYqewhGo7 +2lWPQUsjoDANBgkqhkiG9w0BAQQFAAOBgQBvdYVoBfd4RV/xWSMXIcgw/i5OiwyX +MsenQePll51MpglfArd7pUipUalCqlJt/Gs8kD16Ih1z1yuWYVTMlnDZ0PwbIOYn ++Jr8XLF9b1SMJt6PwckZZ0LZdIi2KwGAxVsIW1kjJAqu9o4YH37XW37yYdQRxfvv +lDiQlgX0JtmLgA== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC9aHAEOzjdqSFF848Cj86TwfaMwejxRuhepAETvotA4k+kJ/Gm +1I8KRz1PpRsrPN0JaW5EFVA+hb/+C8rYoZOjfT6/33hAlXEmdtHSON1l432GpNeH +Ula2ZBjTDF6ipp56rZAHQ9KCTewO8oHH/EblYldJL5Pf9+ngjMDB6yJn4QIDAQAB +AoGACCuYIWaYll80UzslYRvo8lC8nOfEb5v6bBKxBTQD98GLY+5hKywiG3RlPalG +mb/fXQeSPReaRYgpdwD1OBEIOEMW9kLyqpzokC0xjpZ+MwsuJTlxCesk5GEsMa3o +wC3QMmiRA7qrZ/SzTtwrs++9mZ/pxp8JZ6pKYUj8SE7/vV0CQQDz8Ix2t40E16hx +04+XhClnGqydZJyLLSxcTU3ZVhYxL+efo/5hZ8tKpkcDi8wq6T03BOKrKxrlIW55 +qDRNM24rAkEAxsWzu/rJhIouQyNoYygEIEYzFRlTQyZSg59u6dNiewMn27dOAbyc +YT7B6da7e74QttTXo0lIllsX2S38+XsIIwJBANSRuIU3G66tkr5l4gnhhAaxqtuY +sgVhvvdL8dvC9aG1Ifzt9hzBSthpHxbK+oYmK07HdhI8hLpIMLHYzoK7n3MCQEy4 +4rccBcxyyYiAkjozp+QNNIpgTBMPJ6pGT7lRLiHtBeV4y1NASdv/LTnk+Fi69Bid +7t3H24ytfHcHmS1yn6ECQF6Jmh4C7dlvp59zXp+t+VsXxa/8sq41vKNIj0Rx9vh5 +xp9XL0C5ZpgmBnsTydP9pmkiL4ltLbMX0wJU6N2cmFw= +-----END RSA PRIVATE KEY----- diff --git a/demos/cms/signer2.pem b/demos/cms/signer2.pem new file mode 100644 index 0000000..25e23d1 --- /dev/null +++ b/demos/cms/signer2.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIICpjCCAg+gAwIBAgIJAJ+rfmEoLQRiMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV +BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv +dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTgyOTQ0 +WhcNMTcwNDA5MTgyOTQ0WjBWMQswCQYDVQQGEwJVSzElMCMGA1UEAxMcT3BlblNT +TCB0ZXN0IFMvTUlNRSBzaWduZXIgMjEgMB4GCSqGSIb3DQEJARYRdGVzdDJAb3Bl +bnNzbC5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANco7VPgX9vcGwmZ +jYqjq1JiR7M38dsMNhuJyLRVjJ5/cpFluQydQuG1PhzOJ8zfYVFicOXKvbYuKuXW +ozZIwzqEqWsNf36KHTLS6yOMG8I13cRInh+fAIKq9Z8Eh65I7FJzVsNsfEQrGfEW +GMA8us24IaSvP3QkbfHJn/4RaKznAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI +AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW +BBRlrLQJUB8uAa4q8B2OqvvTXonF5zAfBgNVHSMEGDAWgBRHUypxCXFQYqewhGo7 +2lWPQUsjoDANBgkqhkiG9w0BAQQFAAOBgQBQbi2juGALg2k9m1hKpzR2lCGmGO3X +h3Jh/l0vIxDr0RTgP2vBrtITlx655P/o1snoeTIpYG8uUnFnTE/6YakdayAIlxV4 +aZl63AivZMpQB5SPaPH/jEsGJ8UQMfdiy4ORWIULupuPKlKwODNw7tVhQIACS/DR +2aX6rl2JEuJ5Yg== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDXKO1T4F/b3BsJmY2Ko6tSYkezN/HbDDYbici0VYyef3KRZbkM +nULhtT4czifM32FRYnDlyr22Lirl1qM2SMM6hKlrDX9+ih0y0usjjBvCNd3ESJ4f +nwCCqvWfBIeuSOxSc1bDbHxEKxnxFhjAPLrNuCGkrz90JG3xyZ/+EWis5wIDAQAB +AoGAUTB2bcIrKfGimjrBOGGOUmYXnD8uGnQ/LqENhU8K4vxApTD3ZRUqmbUknQYF +6r8YH/e/llasw8QkF9qod+F5GTgsnyh/aMidFHKrXXbf1662scz9+S6crSXq9Eb2 +CL57f6Kw61k6edrz8zHdA+rnTK00hzgzKCP4ZL5k8/55ueECQQD+BK+nsKi6CcKf +m3Mh61Sf2Icm5JlMCKaihlbnh78lBN1imYUAfHJEnQ1ujxXB94R+6o9S+XrWTnTX +2m/JNIfpAkEA2NaidX7Sv5jnRPkwJ02Srl0urxINLmg4bU0zmM3VoMklYBHWnMyr +upPZGPh5TzCa+g6FTBmU8XK61wvnEKNcTwJBAM24VdnlBIDGbsx8RJ3vzLU30xz4 +ff5J80okqjUQhwkgC3tTAZgHMTPITZyAXQqdvrxakoCMc6MkHxTBX08AMCECQHHL +SdyxXrYv7waSY0PtANJCkpJLveEhzqMFxdMmCjtj9BpTojYNbv3uQxtIopj9YAdk +gW2ray++zvC2DV/86x8CQH4UJwgO6JqU4bSgi6HiRNjDg26tJ0Beu8jjl1vrkIVX +pHFwSUeLZUsT2/iTUSgYH4uYiZPgYNcKTCT9W6se30A= +-----END RSA PRIVATE KEY----- diff --git a/demos/easy_tls/Makefile b/demos/easy_tls/Makefile new file mode 100644 index 0000000..2080700 --- /dev/null +++ b/demos/easy_tls/Makefile @@ -0,0 +1,123 @@ +# Makefile for easy-tls example application (rudimentary client and server) +# $Id: Makefile,v 1.2 2001/09/18 09:15:40 bodo Exp $ + +SOLARIS_CFLAGS=-Wall -pedantic -g -O2 +SOLARIS_LIBS=-lxnet + +LINUX_CFLAGS=-Wall -pedantic -g -O2 +LINUX_LIBS= + + +auto-all: + case `uname -s` in \ + SunOS) echo Using SunOS configuration; \ + make SYSCFLAGS="$(SOLARIS_CFLAGS)" SYSLIBS="$(SOLARIS_LIBS)" all;; \ + Linux) echo Using Linux configuration; \ + make SYSCFLAGS="$(LINUX_CFLAGS)" SYSLIBS="$(LINUX_LIBS)" all;; \ + *) echo "unknown system"; exit 1;; \ + esac + +all: test TAGS + +# For adapting this Makefile to a different system, only the following +# definitions should need customizing: + +OPENSSLDIR=../.. +CC=gcc + +SYSCFLAGS=whatever +SYSLIBS=whatever + + +############################################################################# +# +# SSLeay/OpenSSL imports +# +# OPENSSLDIR (set above) can be either the directory where OpenSSL is +# installed or the directory where it was compiled. + +# We rely on having a new OpenSSL release where include files +# have names like (not just ). +OPENSSLINCLUDES=-I$(OPENSSLDIR)/include + +# libcrypto.a and libssl.a are directly in $(OPENSSLDIR) if this is +# the compile directory, or in $(OPENSSLDIR)/lib if we use an installed +# library. With the following definition, we can handle either case. +OPENSSLLIBS=-L$(OPENSSLDIR) -L$(OPENSSLDIR)/lib -lssl -lcrypto + + +############################################################################# +# +# Stuff for handling the source files +# + +SOURCES=easy-tls.c test.c +HEADERS=easy-tls.h test.h +DOCSandEXAMPLESetc=Makefile cert.pem cacerts.pem +EVERYTHING=$(SOURCES) $(HEADERS) $(DOCSandEXAMPLESetc) + +ls: ls-l +ls-l: + ls -l $(EVERYTHING) +# For RCS: +tag: + -rcs -n_`date +%y%m%d`: $(EVERYTHING) + rcs -nMYTAG $(EVERYTHING) + rcs -nMYTAG: $(EVERYTHING) +diff: + -rcsdiff -rMYTAG -u $(EVERYTHING) +today: + -rcsdiff -r_`date +%y%m%d` -u $(EVERYTHING) +ident: + for a in $(EVERYTHING); do ident $$a; done + +# Distribution .tar: +easy-tls.tar.gz: $(EVERYTHING) + tar cvf - $(EVERYTHING) | \ + gzip -9 > easy-tls.tar.gz + +# Working .tar: +tls.tgz: $(EVERYTHING) + tar cfv - `find . -type f -a ! -name '*.tgz' -a ! -name '*.tar.gz'` | \ + gzip -9 > tls.tgz + +# For emacs: +etags: TAGS +TAGS: $(SOURCES) $(HEADERS) + -etags $(SOURCES) $(HEADERS) + + +############################################################################# +# +# Compilation +# +# The following definitions are system dependent (and hence defined +# at the beginning of this Makefile, where they are more easily found): + +### CC=gcc +### SYSCFLAGS=-Wall -pedantic -g -O2 +### SYSLIBS=-lxnet + +EXTRACFLAGS=-DTLS_APP=\"test.h\" +# EXTRACFLAGS=-DTLS_APP=\"test.h\" -DDEBUG_TLS + +# +# The rest shouldn't need to be touched. +# +LDFLAGS=$(SYSLIBS) $(OPENSSLLIBS) +INCLUDES=$(OPENSSLINCLUDES) +CFLAGS=$(SYSCFLAGS) $(EXTRACFLAGS) $(INCLUDES) + +OBJS=easy-tls.o test.o + +clean: + @rm -f test + @rm -f TAGS + @rm -f *.o + @rm -f core + +test: $(OBJS) + $(CC) $(OBJS) $(LDFLAGS) -o test + +test.o: $(HEADERS) +easy-tls.o: $(HEADERS) diff --git a/demos/easy_tls/README b/demos/easy_tls/README new file mode 100644 index 0000000..816a580 --- /dev/null +++ b/demos/easy_tls/README @@ -0,0 +1,65 @@ +easy_tls - generic SSL/TLS proxy +======== + +(... and example for non-blocking SSL/TLS I/O multiplexing.) + + + easy_tls.c, easy_tls.h: + + Small generic SSL/TLS proxy library: With a few function calls, + an application socket will be replaced by a pipe handled by a + separate SSL/TLS proxy process. This allows easily adding + SSL/TLS support to many programs not originally designed for it. + + [Actually easy_tls.c is not a proper library: Customization + requires defining preprocessor macros while compiling it. + This is quite confusing, so I'll probably change it.] + + These files may be used under the OpenSSL license. + + + + test.c, test.h, Makefile, cert.pem, cacerts.pem: + + Rudimentary example program using the easy_tls library, and + example key and certificates for it. Usage examples: + + $ ./test 8443 # create server listening at port 8443 + $ ./test 127.0.0.1 8443 # create client, connect to port 8443 + # at IP address 127.0.0.1 + + 'test' will not automatically do SSL/TLS, or even read or write + data -- it must be told to do so on input lines starting + with a command letter. 'W' means write a line, 'R' means + read a line, 'C' means close the connection, 'T' means + start an SSL/TLS proxy. E.g. (user input tagged with '*'): + + * R + <<< 220 mail.example.net + * WSTARTTLS + >>> STARTTLS + * R + <<< 220 Ready to start TLS + * T + test_process_init(fd = 3, client_p = 1, apparg = (nil)) + +++ `E:self signed certificate in certificate chain' + +++ `<... certificate info ...>' + * WHELO localhost + >>> HELO localhost + R + <<< 250 mail.example.net + + You can even do SSL/TLS over SSL/TLS over SSL/TLS ... by using + 'T' multiple times. I have no idea why you would want to though. + + +This code is rather old. When I find time I will update anything that +should be changed, and improve code comments. To compile the sample +program 'test' on platforms other then Linux or Solaris, you will have +to edit the Makefile. + +As noted above, easy_tls.c will be changed to become a library one +day, which means that future revisions will not be fully compatible to +the current version. + +Bodo Möller diff --git a/demos/easy_tls/cacerts.pem b/demos/easy_tls/cacerts.pem new file mode 100644 index 0000000..acc70ba --- /dev/null +++ b/demos/easy_tls/cacerts.pem @@ -0,0 +1,18 @@ +$Id: cacerts.pem,v 1.1 2001/09/17 19:06:57 bodo Exp $ + +issuer= /C=AU/ST=Queensland/O=CryptSoft Pty Ltd/CN=Test PCA (1024 bit) +subject=/C=AU/ST=Queensland/O=CryptSoft Pty Ltd/CN=Test CA (1024 bit) +-----BEGIN CERTIFICATE----- +MIICJjCCAY8CAQAwDQYJKoZIhvcNAQEEBQAwXDELMAkGA1UEBhMCQVUxEzARBgNV +BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRwwGgYD +VQQDExNUZXN0IFBDQSAoMTAyNCBiaXQpMB4XDTk3MDYwOTEzNTc0M1oXDTAxMDYw +OTEzNTc0M1owWzELMAkGA1UEBhMCQVUxEzARBgNVBAgTClF1ZWVuc2xhbmQxGjAY +BgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYDVQQDExJUZXN0IENBICgxMDI0 +IGJpdCkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKO7o8t116VP6cgybTsZ +DCZhr95nYlZuya3aCi1IKoztqwWnjbmDFIriOqGFPrZQ+moMETC9D59iRW/dFXSv +1F65ka/XY2hLh9exCCo7XuUcDs53Qp3bI3AmMqHjgzE8oO3ajyJAzJkTTOUecQU2 +mw/gI4tMM0LqWMQS7luTy4+xAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAM7achv3v +hLQJcv/65eGEpBXM40ZDVoFQFFJWaY5p883HTqLB1x4FdzsXHH0QKBTcKpWwqyu4 +YDm3fb8oDugw72bCzfyZK/zVZPR/hVlqI/fvU109Qoc+7oPvIXWky71HfcK6ZBCA +q30KIqGM/uoM60INq97qjDmCJapagcNBGQs= +-----END CERTIFICATE----- diff --git a/demos/easy_tls/cert.pem b/demos/easy_tls/cert.pem new file mode 100644 index 0000000..364fe10 --- /dev/null +++ b/demos/easy_tls/cert.pem @@ -0,0 +1,31 @@ +$Id: cert.pem,v 1.1 2001/09/17 19:06:57 bodo Exp $ + +Example certificate and key. + +-----BEGIN CERTIFICATE----- +MIIB1jCCAT8CAQEwDQYJKoZIhvcNAQEEBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV +BAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 +ZDAeFw05OTA1MDEwMTI2MzVaFw05OTA1MzEwMTI2MzVaMCIxCzAJBgNVBAYTAkRF +MRMwEQYDVQQDEwpUZXN0c2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQD6I3oDKiexwwlkzjar69AIFnVUaG85LtCege2R+CtIDlkQYw68/8MbT3ou0pdF +AcL9IGiYY3Y0SHM9PqF00RO1MCtNpqTnF3ScLpbmggGjKilmWYn2ai7emdjMjXVL +tzWW2xGgIGATWQN32KgfJng4jXi1UjEiyLhkw0Zf1I/ggwIDAQABMA0GCSqGSIb3 +DQEBBAUAA4GBAMgM+sbAk8DfjSfa+Rf2gcGXmbrvZAzKzC+5RU3kaq/NyxIXAGco +9dZjozzWfN/xuGup5boFk+KrP+xdgsaqGHsyzlgEoqz4ekqLjQeVbnoj339hVFU9 +MhPi6JULPxjXKumjfX2LLNkikW5puz8Df3UiX0EiaJvd7EwP8J75tiUT +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQD6I3oDKiexwwlkzjar69AIFnVUaG85LtCege2R+CtIDlkQYw68 +/8MbT3ou0pdFAcL9IGiYY3Y0SHM9PqF00RO1MCtNpqTnF3ScLpbmggGjKilmWYn2 +ai7emdjMjXVLtzWW2xGgIGATWQN32KgfJng4jXi1UjEiyLhkw0Zf1I/ggwIDAQAB +AoGANST8c1etf1MU19oIO5aqaE19OCXIG7oakNLCCtVTPMfvnE+vffBJH7BPIUuU +4BBzwRv1nQrkvk72TPjVjOAu81B1SStKQueun2flVuYxp9NyupNWCBley4QdohlP +I92ml2tzTSPmNIoA6jdGyNzFcGchapRRmejsC39F1RUbHQECQQD9KX81Wt8ZOrri +dWiEXja1L3X8Bkb9vvUjVMQDTJJPxBJjehC6eurgE6PP6SJD5p/f3RHPCcLr8tSM +D4P/OpKhAkEA/PFNlhIZUDKK6aTvG2mn7qQ5phbadOoyN1Js3ttWG5OMOZ6b/QlC +Wvp84h44506BIlv+Tg2YAI0AdBUrf7oEowJAM4joAVd/ROaEtqbJ4PBA2L9RmD06 +5FqkEk4mHLnQqvYx/BgUIbH18ClvVlqSBBqFfw/EmU3WZSuogt6Bs0ocIQJBAOxB +AoPiYcxbeQ5kZIVJOXaX49SzUdaUDNVJYrEBUzsspHQJJo/Avz606kJVkjbSR6Ft +JWmIHuqcyMikIV4KxFsCQQCU2evoVjVsqkkbHi7W28f73PGBsyu0KIwlK7nu4h08 +Daf7TAI+A6jW/WRUsJ6dFhUYi7/Jvkcdrlnbgm2fxziX +-----END RSA PRIVATE KEY----- diff --git a/demos/easy_tls/easy-tls.c b/demos/easy_tls/easy-tls.c new file mode 100644 index 0000000..9cd8314 --- /dev/null +++ b/demos/easy_tls/easy-tls.c @@ -0,0 +1,1240 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ +/* + * easy-tls.c -- generic TLS proxy. + * $Id: easy-tls.c,v 1.4 2002/03/05 09:07:16 bodo Exp $ + */ +/* + (c) Copyright 1999 Bodo Moeller. All rights reserved. + + This is free software; you can redistributed and/or modify it + unter the terms of either + - the GNU General Public License as published by the + Free Software Foundation, version 1, or (at your option) + any later version, + or + - the following license: +*/ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that each of the following + * conditions is met: + * + * 1. Redistributions qualify as "freeware" or "Open Source Software" under + * one of the following terms: + * + * (a) Redistributions are made at no charge beyond the reasonable cost of + * materials and delivery. + * + * (b) Redistributions are accompanied by a copy of the Source Code + * or by an irrevocable offer to provide a copy of the Source Code + * for up to three years at the cost of materials and delivery. + * Such redistributions must allow further use, modification, and + * redistribution of the Source Code under substantially the same + * terms as this license. + * + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 3. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 4. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by Bodo Moeller." + * (If available, substitute umlauted o for oe.) + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Bodo Moeller." + * + * THIS SOFTWARE IS PROVIDED BY BODO MOELLER ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BODO MOELLER OR + * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Attribution for OpenSSL library: + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/) + */ + +static char const rcsid[] = +"$Id: easy-tls.c,v 1.4 2002/03/05 09:07:16 bodo Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef NO_RSA + #include +#endif +#include +#include +#include + +#if OPENSSL_VERSION_NUMBER < 0x00904000L /* 0.9.4-dev */ +# error "This program needs OpenSSL 0.9.4 or later." +#endif + +#include "easy-tls.h" /* include after if both are needed */ + +#if TLS_INFO_SIZE > PIPE_BUF +# if PIPE_BUF < 512 +# error "PIPE_BUF < 512" /* non-POSIX */ +# endif +# error "TLS_INFO_SIZE > PIPE_BUF" +#endif + +/*****************************************************************************/ + +#ifdef TLS_APP +# include TLS_APP +#endif + +/* Applications can define: + * TLS_APP_PROCESS_INIT -- void ...(int fd, int client_p, void *apparg) + * TLS_CUMULATE_ERRORS + * TLS_ERROR_BUFSIZ + * TLS_APP_ERRFLUSH -- void ...(int child_p, char *, size_t, void *apparg) + */ + +#ifndef TLS_APP_PROCESS_INIT +# define TLS_APP_PROCESS_INIT(fd, client_p, apparg) ((void) 0) +#endif + +#ifndef TLS_ERROR_BUFSIZ +# define TLS_ERROR_BUFSIZ (10*160) +#endif +#if TLS_ERROR_BUFSIZ < 2 /* {'\n',0} */ +# error "TLS_ERROR_BUFSIZE is too small." +#endif + +#ifndef TLS_APP_ERRFLUSH +# define TLS_APP_ERRFLUSH tls_app_errflush +static void +tls_app_errflush(int child_p, char *errbuf, size_t num, void *apparg) +{ + fputs(errbuf, stderr); +} +#endif + +/*****************************************************************************/ + +#ifdef DEBUG_TLS +# define DEBUG_MSG(x) fprintf(stderr," %s\n",x) +# define DEBUG_MSG2(x,y) fprintf(stderr, " %s: %d\n",x,y) +static int tls_loop_count = 0; +static int tls_select_count = 0; +#else +# define DEBUG_MSG(x) (void)0 +# define DEBUG_MSG2(x,y) (void)0 +#endif + +static void tls_rand_seed_uniquely(void); +static void tls_proxy(int clear_fd, int tls_fd, int info_fd, SSL_CTX *ctx, int client_p); +static int tls_socket_nonblocking(int fd); + +static int tls_child_p = 0; +static void *tls_child_apparg; + + +struct tls_start_proxy_args +tls_start_proxy_defaultargs(void) +{ + struct tls_start_proxy_args ret; + + ret.fd = -1; + ret.client_p = -1; + ret.ctx = NULL; + ret.pid = NULL; + ret.infofd = NULL; + + return ret; +} + +/* Slice in TLS proxy process at fd. + * Return value: + * 0 ok (*pid is set to child's PID if pid != NULL), + * < 0 look at errno + * > 0 other error + * (return value encodes place of error) + * + */ +int +tls_start_proxy(struct tls_start_proxy_args a, void *apparg) +{ + int fds[2] = {-1, -1}; + int infofds[2] = {-1, -1}; + int r, getfd, getfl; + int ret; + + DEBUG_MSG2("tls_start_proxy fd", a.fd); + DEBUG_MSG2("tls_start_proxy client_p", a.client_p); + + if (a.fd == -1 || a.client_p == -1 || a.ctx == NULL) + return 1; + + if (a.pid != NULL) { + *a.pid = 0; + } + if (a.infofd != NULL) { + *a.infofd = -1; + } + + r = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + if (r == -1) + return -1; + if (a.fd >= FD_SETSIZE || fds[0] >= FD_SETSIZE) { + ret = 2; + goto err; + } + if (a.infofd != NULL) { + r = pipe(infofds); + if (r == -1) { + ret = -3; + goto err; + } + } + + r = fork(); + if (r == -1) { + ret = -4; + goto err; + } + if (r == 0) { + DEBUG_MSG("fork"); + tls_child_p = 1; + tls_child_apparg = apparg; + close(fds[1]); + if (infofds[0] != -1) + close(infofds[0]); + TLS_APP_PROCESS_INIT(a.fd, a.client_p, apparg); + DEBUG_MSG("TLS_APP_PROCESS_INIT"); + tls_proxy(fds[0], a.fd, infofds[1], a.ctx, a.client_p); + exit(0); + } + if (a.pid != NULL) + *a.pid = r; + if (infofds[1] != -1) { + close(infofds[1]); + infofds[1] = -1; + } + /* install fds[1] in place of fd: */ + close(fds[0]); + fds[0] = -1; + getfd = fcntl(a.fd, F_GETFD); + getfl = fcntl(a.fd, F_GETFL); + r = dup2(fds[1], a.fd); + close(fds[1]); + fds[1] = -1; + if (r == -1) { + ret = -5; + goto err; + } + if (getfd != 1) + fcntl(a.fd, F_SETFD, getfd); + if (getfl & O_NONBLOCK) + (void)tls_socket_nonblocking(a.fd); + if (a.infofd != NULL) + *a.infofd = infofds[0]; + return 0; + + err: + if (fds[0] != -1) + close(fds[0]); + if (fds[1] != -1) + close(fds[1]); + if (infofds[0] != -1) + close(infofds[0]); + if (infofds[1] != -1) + close(infofds[1]); + return ret; +} + +/*****************************************************************************/ + +static char errbuf[TLS_ERROR_BUFSIZ]; +static size_t errbuf_i = 0; + +static void +tls_errflush(void *apparg) +{ + if (errbuf_i == 0) + return; + + assert(errbuf_i < sizeof errbuf); + assert(errbuf[errbuf_i] == 0); + if (errbuf_i == sizeof errbuf - 1) { + /* make sure we have a newline, even if string has been truncated */ + errbuf[errbuf_i - 1] = '\n'; + } + + /* TLS_APP_ERRFLUSH may modify the string as needed, + * e.g. substitute other characters for \n for convenience */ + TLS_APP_ERRFLUSH(tls_child_p, errbuf, errbuf_i, apparg); + + errbuf_i = 0; +} + +static void +tls_errprintf(int flush, void *apparg, const char *fmt, ...) +{ + va_list args; + int r; + + if (errbuf_i < sizeof errbuf - 1) { + size_t n; + + va_start(args, fmt); + n = (sizeof errbuf) - errbuf_i; + r = vsnprintf(errbuf + errbuf_i, n, fmt, args); + if (r >= n) + r = n - 1; + if (r >= 0) { + errbuf_i += r; + } else { + errbuf_i = sizeof errbuf - 1; + errbuf[errbuf_i] = '\0'; + } + assert(errbuf_i < sizeof errbuf); + assert(errbuf[errbuf_i] == 0); + } +#ifndef TLS_CUMULATE_ERRORS + tls_errflush(apparg); +#else + if (flush) + tls_errflush(apparg); +#endif +} + +/* app_prefix.. are for additional information provided by caller. + * If OpenSSL error queue is empty, print default_text ("???" if NULL). + */ +static char * +tls_openssl_errors(const char *app_prefix_1, const char *app_prefix_2, const char *default_text, void *apparg) +{ + static char reasons[255]; + size_t reasons_i; + unsigned long err; + const char *file; + int line; + const char *data; + int flags; + char *errstring; + int printed_something = 0; + + reasons_i = 0; + + assert(app_prefix_1 != NULL); + assert(app_prefix_2 != NULL); + + if (default_text == NULL) + default_text = "?""?""?"; + + while ((err = ERR_get_error_line_data(&file,&line,&data,&flags)) != 0) { + if (reasons_i < sizeof reasons) { + size_t n; + int r; + + n = (sizeof reasons) - reasons_i; + r = snprintf(reasons + reasons_i, n, "%s%s", (reasons_i > 0 ? ", " : ""), ERR_reason_error_string(err)); + if (r >= n) + r = n - 1; + if (r >= 0) { + reasons_i += r; + } else { + reasons_i = sizeof reasons; + } + assert(reasons_i <= sizeof reasons); + } + + errstring = ERR_error_string(err, NULL); + assert(errstring != NULL); + tls_errprintf(0, apparg, "OpenSSL error%s%s: %s:%s:%d:%s\n", app_prefix_1, app_prefix_2, errstring, file, line, (flags & ERR_TXT_STRING) ? data : ""); + printed_something = 1; + } + + if (!printed_something) { + assert(reasons_i == 0); + snprintf(reasons, sizeof reasons, "%s", default_text); + tls_errprintf(0, apparg, "OpenSSL error%s%s: %s\n", app_prefix_1, app_prefix_2, default_text); + } + +#ifdef TLS_CUMULATE_ERRORS + tls_errflush(apparg); +#endif + assert(errbuf_i == 0); + + return reasons; +} + +/*****************************************************************************/ + +static int tls_init_done = 0; + +static int +tls_init(void *apparg) +{ + if (tls_init_done) + return 0; + + SSL_load_error_strings(); + if (!SSL_library_init() /* aka SSLeay_add_ssl_algorithms() */ ) { + tls_errprintf(1, apparg, "SSL_library_init failed.\n"); + return -1; + } + tls_init_done = 1; + tls_rand_seed(); + return 0; +} + +/*****************************************************************************/ + +static void +tls_rand_seed_uniquely(void) +{ + struct { + pid_t pid; + time_t time; + void *stack; + } data; + + data.pid = getpid(); + data.time = time(NULL); + data.stack = (void *)&data; + + RAND_seed((const void *)&data, sizeof data); +} + +void +tls_rand_seed(void) +{ + struct { + struct utsname uname; + int uname_1; + int uname_2; + uid_t uid; + uid_t euid; + gid_t gid; + gid_t egid; + } data; + + data.uname_1 = uname(&data.uname); + data.uname_2 = errno; /* Let's hope that uname fails randomly :-) */ + + data.uid = getuid(); + data.euid = geteuid(); + data.gid = getgid(); + data.egid = getegid(); + + RAND_seed((const void *)&data, sizeof data); + tls_rand_seed_uniquely(); +} + +static int tls_rand_seeded_p = 0; + +#define my_MIN_SEED_BYTES 256 /* struct stat can be larger than 128 */ +int +tls_rand_seed_from_file(const char *filename, size_t n, void *apparg) +{ + /* Seed OpenSSL's random number generator from file. + Try to read n bytes if n > 0, whole file if n == 0. */ + + int r; + + if (tls_init(apparg) == -1) + return -1; + tls_rand_seed(); + + r = RAND_load_file(filename, (n > 0 && n < LONG_MAX) ? (long)n : LONG_MAX); + /* r is the number of bytes filled into the random number generator, + * which are taken from "stat(filename, ...)" in addition to the + * file contents. + */ + assert(1 < my_MIN_SEED_BYTES); + /* We need to detect at least those cases when the file does not exist + * at all. With current versions of OpenSSL, this should do it: */ + if (n == 0) + n = my_MIN_SEED_BYTES; + if (r < n) { + tls_errprintf(1, apparg, "rand_seed_from_file: could not read %d bytes from %s.\n", n, filename); + return -1; + } else { + tls_rand_seeded_p = 1; + return 0; + } +} + +void +tls_rand_seed_from_memory(const void *buf, size_t n) +{ + size_t i = 0; + + while (i < n) { + size_t rest = n - i; + int chunk = rest < INT_MAX ? (int)rest : INT_MAX; + RAND_seed((const char *)buf + i, chunk); + i += chunk; + } + tls_rand_seeded_p = 1; +} + + +/*****************************************************************************/ + +struct tls_x509_name_string { + char str[100]; +}; + +static void +tls_get_x509_subject_name_oneline(X509 *cert, struct tls_x509_name_string *namestring) +{ + X509_NAME *name; + + if (cert == NULL) { + namestring->str[0] = '\0'; + return; + } + + name = X509_get_subject_name(cert); /* does not increment any reference counter */ + + assert(sizeof namestring->str >= 4); /* "?" or "...", plus 0 */ + + if (name == NULL) { + namestring->str[0] = '?'; + namestring->str[1] = 0; + } else { + size_t len; + + X509_NAME_oneline(name, namestring->str, sizeof namestring->str); + len = strlen(namestring->str); + assert(namestring->str[len] == 0); + assert(len < sizeof namestring->str); + + if (len+1 == sizeof namestring->str) { + /* (Probably something was cut off.) + * Does not really work -- X509_NAME_oneline truncates after + * name components, we cannot tell from the result whether + * anything is missing. */ + + assert(namestring->str[len] == 0); + namestring->str[--len] = '.'; + namestring->str[--len] = '.'; + namestring->str[--len] = '.'; + } + } +} + +/*****************************************************************************/ + +/* to hinder OpenSSL from asking for passphrases */ +static int +no_passphrase_callback(char *buf, int num, int w, void *arg) +{ + return -1; +} + +#if OPENSSL_VERSION_NUMBER >= 0x00907000L +static int +verify_dont_fail_cb(X509_STORE_CTX *c, void *unused_arg) +#else +static int +verify_dont_fail_cb(X509_STORE_CTX *c) +#endif +{ + int i; + + i = X509_verify_cert(c); /* sets c->error */ +#if OPENSSL_VERSION_NUMBER >= 0x00905000L /* don't allow unverified + * certificates -- they could + * survive session reuse, but + * OpenSSL < 0.9.5-dev does not + * preserve their verify_result */ + if (i == 0) + return 1; + else +#endif + return i; +} + +static DH *tls_dhe1024 = NULL; /* generating these takes a while, so do it just once */ + +void +tls_set_dhe1024(int i, void *apparg) +{ + DSA *dsaparams; + DH *dhparams; + const char *seed[] = { ";-) :-( :-) :-( ", + ";-) :-( :-) :-( ", + "Random String no. 12", + ";-) :-( :-) :-( ", + "hackers have even mo", /* from jargon file */ + }; + unsigned char seedbuf[20]; + + tls_init(apparg); + if (i >= 0) { + i %= sizeof seed / sizeof seed[0]; + assert(strlen(seed[i]) == 20); + memcpy(seedbuf, seed[i], 20); + dsaparams = DSA_generate_parameters(1024, seedbuf, 20, NULL, NULL, 0, NULL); + } else { + /* random parameters (may take a while) */ + dsaparams = DSA_generate_parameters(1024, NULL, 0, NULL, NULL, 0, NULL); + } + + if (dsaparams == NULL) { + tls_openssl_errors("", "", NULL, apparg); + return; + } + dhparams = DSA_dup_DH(dsaparams); + DSA_free(dsaparams); + if (dhparams == NULL) { + tls_openssl_errors("", "", NULL, apparg); + return; + } + if (tls_dhe1024 != NULL) + DH_free(tls_dhe1024); + tls_dhe1024 = dhparams; +} + +struct tls_create_ctx_args +tls_create_ctx_defaultargs(void) +{ + struct tls_create_ctx_args ret; + + ret.client_p = 0; + ret.certificate_file = NULL; + ret.key_file = NULL; + ret.ca_file = NULL; + ret.verify_depth = -1; + ret.fail_unless_verified = 0; + ret.export_p = 0; + + return ret; +} + +SSL_CTX * +tls_create_ctx(struct tls_create_ctx_args a, void *apparg) +{ + int r; + static long context_num = 0; + SSL_CTX *ret; + const char *err_pref_1 = "", *err_pref_2 = ""; + + if (tls_init(apparg) == -1) + return NULL; + + ret = SSL_CTX_new((a.client_p? SSLv23_client_method:SSLv23_server_method)()); + + if (ret == NULL) + goto err; + + SSL_CTX_set_default_passwd_cb(ret, no_passphrase_callback); + SSL_CTX_set_mode(ret, SSL_MODE_ENABLE_PARTIAL_WRITE); + + if ((a.certificate_file != NULL) || (a.key_file != NULL)) { + if (a.key_file == NULL) { + tls_errprintf(1, apparg, "Need a key file.\n"); + goto err_return; + } + if (a.certificate_file == NULL) { + tls_errprintf(1, apparg, "Need a certificate chain file.\n"); + goto err_return; + } + + if (!SSL_CTX_use_PrivateKey_file(ret, a.key_file, SSL_FILETYPE_PEM)) + goto err; + if (!tls_rand_seeded_p) { + /* particularly paranoid people may not like this -- + * so provide your own random seeding before calling this */ + if (tls_rand_seed_from_file(a.key_file, 0, apparg) == -1) + goto err_return; + } + if (!SSL_CTX_use_certificate_chain_file(ret, a.certificate_file)) + goto err; + if (!SSL_CTX_check_private_key(ret)) { + tls_errprintf(1, apparg, "Private key \"%s\" does not match certificate \"%s\".\n", a.key_file, a.certificate_file); + goto err_peek; + } + } + + if ((a.ca_file != NULL) || (a.verify_depth > 0)) { + context_num++; + r = SSL_CTX_set_session_id_context(ret, (const void *)&context_num, (unsigned int)sizeof context_num); + if (!r) + goto err; + + SSL_CTX_set_verify(ret, SSL_VERIFY_PEER | (a.fail_unless_verified ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0), 0); + if (!a.fail_unless_verified) + SSL_CTX_set_cert_verify_callback(ret, verify_dont_fail_cb, NULL); + + if (a.verify_depth > 0) + SSL_CTX_set_verify_depth(ret, a.verify_depth); + + if (a.ca_file != NULL) { + r = SSL_CTX_load_verify_locations(ret, a.ca_file, NULL /* no CA-directory */); /* does not report failure if file does not exist ... */ + if (!r) { + err_pref_1 = " while processing certificate file "; + err_pref_2 = a.ca_file; + goto err; + } + + if (!a.client_p) { + /* SSL_load_client_CA_file is a misnomer, it just creates a list of CNs. */ + SSL_CTX_set_client_CA_list(ret, SSL_load_client_CA_file(a.ca_file)); + /* SSL_CTX_set_client_CA_list does not have a return value; + * it does not really need one, but make sure + * (we really test if SSL_load_client_CA_file worked) */ + if (SSL_CTX_get_client_CA_list(ret) == NULL) { + tls_errprintf(1, apparg, "Could not set client CA list from \"%s\".\n", a.ca_file); + goto err_peek; + } + } + } + } + + if (!a.client_p) { + if (tls_dhe1024 == NULL) { + int i; + + RAND_bytes((unsigned char *) &i, sizeof i); + /* make sure that i is non-negative -- pick one of the provided + * seeds */ + if (i < 0) + i = -i; + if (i < 0) + i = 0; + tls_set_dhe1024(i, apparg); + if (tls_dhe1024 == NULL) + goto err_return; + } + + if (!SSL_CTX_set_tmp_dh(ret, tls_dhe1024)) + goto err; + + /* avoid small subgroup attacks: */ + SSL_CTX_set_options(ret, SSL_OP_SINGLE_DH_USE); + } + +#ifndef NO_RSA + if (!a.client_p && a.export_p) { + RSA *tmpkey; + + tmpkey = RSA_generate_key(512, RSA_F4, 0, NULL); + if (tmpkey == NULL) + goto err; + if (!SSL_CTX_set_tmp_rsa(ret, tmpkey)) { + RSA_free(tmpkey); + goto err; + } + RSA_free(tmpkey); /* SSL_CTX_set_tmp_rsa uses a duplicate. */ + } +#endif + + return ret; + + err_peek: + if (!ERR_peek_error()) + goto err_return; + err: + tls_openssl_errors(err_pref_1, err_pref_2, NULL, apparg); + err_return: + if (ret != NULL) + SSL_CTX_free(ret); + return NULL; +} + + +/*****************************************************************************/ + +static int +tls_socket_nonblocking(int fd) +{ + int v, r; + + v = fcntl(fd, F_GETFL, 0); + if (v == -1) { + if (errno == EINVAL) + return 0; /* already shut down -- ignore */ + return -1; + } + r = fcntl(fd, F_SETFL, v | O_NONBLOCK); + if (r == -1) { + if (errno == EINVAL) + return 0; /* already shut down -- ignore */ + return -1; + } + return 0; +} + +static int +max(int a, int b) +{ + return a > b ? a : b; +} + +static void +tls_sockets_select(int read_select_1, int read_select_2, int write_select_1, int write_select_2, int seconds /* timeout, -1 means no timeout */) +{ + int maxfd, n; + fd_set reads, writes; + struct timeval timeout; + struct timeval *timeout_p; + + assert(read_select_1 >= -1 && read_select_2 >= -1 && write_select_1 >= -1 && write_select_2 >= -1); + assert(read_select_1 < FD_SETSIZE && read_select_2 < FD_SETSIZE -1 && write_select_1 < FD_SETSIZE -1 && write_select_2 < FD_SETSIZE -1); + + maxfd = max(max(read_select_1, read_select_2), max(write_select_1, write_select_2)); + assert(maxfd >= 0); + + FD_ZERO(&reads); + FD_ZERO(&writes); + + for(n = 0; n < 4; ++n) { + int i = n % 2; + int w = n >= 2; + /* loop over all (i, w) in {0,1}x{0,1} */ + int fd; + + if (i == 0 && w == 0) + fd = read_select_1; + else if (i == 1 && w == 0) + fd = read_select_2; + else if (i == 0 && w == 1) + fd = write_select_1; + else { + assert(i == 1 && w == 1); + fd = write_select_2; + } + + if (fd >= 0) { + if (w == 0) + FD_SET(fd, &reads); + else /* w == 1 */ + FD_SET(fd, &writes); + } + } + + if (seconds >= 0) { + timeout.tv_sec = seconds; + timeout.tv_usec = 0; + timeout_p = &timeout; + } else + timeout_p = NULL; + + DEBUG_MSG2("select no.", ++tls_select_count); + select(maxfd + 1, &reads, &writes, (fd_set *) NULL, timeout_p); + DEBUG_MSG("cont."); +} + +/*****************************************************************************/ + +#define TUNNELBUFSIZE (16*1024) +struct tunnelbuf { + char buf[TUNNELBUFSIZE]; + size_t len; + size_t offset; +}; + +static int tls_connect_attempt(SSL *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref); + +static int tls_accept_attempt(SSL *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref); + +static int tls_write_attempt(SSL *, struct tunnelbuf *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref); + +static int tls_read_attempt(SSL *, struct tunnelbuf *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref); + +static int write_attempt(int fd, struct tunnelbuf *, int *select, int *closed, int *progress); + +static int read_attempt(int fd, struct tunnelbuf *, int *select, int *closed, int *progress); + +static void write_info(SSL *ssl, int *info_fd) +{ + if (*info_fd != -1) { + long v; + int v_ok; + struct tls_x509_name_string peer; + char infobuf[TLS_INFO_SIZE]; + int r; + + DEBUG_MSG("write_info"); + v = SSL_get_verify_result(ssl); + v_ok = (v == X509_V_OK) ? 'A' : 'E'; /* Auth./Error */ + { + X509 *peercert; + + peercert = SSL_get_peer_certificate(ssl); + tls_get_x509_subject_name_oneline(peercert, &peer); + if (peercert != NULL) + X509_free(peercert); + } + if (peer.str[0] == '\0') + v_ok = '0'; /* no cert at all */ + else + if (strchr(peer.str, '\n')) { + /* should not happen, but make sure */ + *strchr(peer.str, '\n') = '\0'; + } + r = snprintf(infobuf, sizeof infobuf, "%c:%s\n%s\n", v_ok, X509_verify_cert_error_string(v), peer.str); + DEBUG_MSG2("snprintf", r); + if (r == -1 || r >= sizeof infobuf) + r = sizeof infobuf - 1; + write(*info_fd, infobuf, r); + close (*info_fd); + *info_fd = -1; + } +} + + +/* tls_proxy expects that all fds are closed after return */ +static void +tls_proxy(int clear_fd, int tls_fd, int info_fd, SSL_CTX *ctx, int client_p) +{ + struct tunnelbuf clear_to_tls, tls_to_clear; + SSL *ssl; + BIO *rbio, *wbio; + int closed, in_handshake; + const char *err_pref_1 = "", *err_pref_2 = ""; + const char *err_def = NULL; + + assert(clear_fd != -1); + assert(tls_fd != -1); + assert(clear_fd < FD_SETSIZE); + assert(tls_fd < FD_SETSIZE); + /* info_fd may be -1 */ + assert(ctx != NULL); + + tls_rand_seed_uniquely(); + + tls_socket_nonblocking(clear_fd); + DEBUG_MSG2("clear_fd", clear_fd); + tls_socket_nonblocking(tls_fd); + DEBUG_MSG2("tls_fd", tls_fd); + + ssl = SSL_new(ctx); + if (ssl == NULL) + goto err; + DEBUG_MSG("SSL_new"); + if (!SSL_set_fd(ssl, tls_fd)) + goto err; + rbio = SSL_get_rbio(ssl); + wbio = SSL_get_wbio(ssl); /* should be the same, but who cares */ + assert(rbio != NULL); + assert(wbio != NULL); + if (client_p) + SSL_set_connect_state(ssl); + else + SSL_set_accept_state(ssl); + + closed = 0; + in_handshake = 1; + tls_to_clear.len = 0; + tls_to_clear.offset = 0; + clear_to_tls.len = 0; + clear_to_tls.offset = 0; + + err_def = "I/O error"; + + /* loop finishes as soon as we detect that one side closed; + * when all (program and OS) buffers have enough space, + * the data from the last succesful read in each direction is transferred + * before close */ + do { + int clear_read_select = 0, clear_write_select = 0, + tls_read_select = 0, tls_write_select = 0, + progress = 0; + int r; + unsigned long num_read = BIO_number_read(rbio), + num_written = BIO_number_written(wbio); + + DEBUG_MSG2("loop iteration", ++tls_loop_count); + + if (in_handshake) { + DEBUG_MSG("in_handshake"); + if (client_p) + r = tls_connect_attempt(ssl, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1); + else + r = tls_accept_attempt(ssl, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1); + if (r != 0) { + write_info(ssl, &info_fd); + goto err; + } + if (closed) + goto err_return; + if (!SSL_in_init(ssl)) { + in_handshake = 0; + write_info(ssl, &info_fd); + } + } + + if (clear_to_tls.len != 0 && !in_handshake) { + assert(!closed); + + r = tls_write_attempt(ssl, &clear_to_tls, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1); + if (r != 0) + goto err; + if (closed) { + assert(progress); + tls_to_clear.offset = 0; + tls_to_clear.len = 0; + } + } + + if (tls_to_clear.len != 0) { + assert(!closed); + + r = write_attempt(clear_fd, &tls_to_clear, &clear_write_select, &closed, &progress); + if (r != 0) + goto err_return; + if (closed) { + assert(progress); + clear_to_tls.offset = 0; + clear_to_tls.len = 0; + } + } + + if (!closed) { + if (clear_to_tls.offset + clear_to_tls.len < sizeof clear_to_tls.buf) { + r = read_attempt(clear_fd, &clear_to_tls, &clear_read_select, &closed, &progress); + if (r != 0) + goto err_return; + if (closed) { + r = SSL_shutdown(ssl); + DEBUG_MSG2("SSL_shutdown", r); + } + } + } + + if (!closed && !in_handshake) { + if (tls_to_clear.offset + tls_to_clear.len < sizeof tls_to_clear.buf) { + r = tls_read_attempt(ssl, &tls_to_clear, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1); + if (r != 0) + goto err; + if (closed) { + r = SSL_shutdown(ssl); + DEBUG_MSG2("SSL_shutdown", r); + } + } + } + + if (!progress) { + DEBUG_MSG("!progress?"); + if (num_read != BIO_number_read(rbio) || num_written != BIO_number_written(wbio)) + progress = 1; + + if (!progress) { + DEBUG_MSG("!progress"); + assert(clear_read_select || tls_read_select || clear_write_select || tls_write_select); + tls_sockets_select(clear_read_select ? clear_fd : -1, tls_read_select ? tls_fd : -1, clear_write_select ? clear_fd : -1, tls_write_select ? tls_fd : -1, -1); + } + } + } while (!closed); + return; + + err: + tls_openssl_errors(err_pref_1, err_pref_2, err_def, tls_child_apparg); + err_return: + return; +} + + +static int +tls_get_error(SSL *ssl, int r, int *write_select, int *read_select, int *closed, int *progress) +{ + int err = SSL_get_error(ssl, r); + + if (err == SSL_ERROR_NONE) { + assert(r > 0); + *progress = 1; + return 0; + } + + assert(r <= 0); + + switch (err) { + case SSL_ERROR_ZERO_RETURN: + assert(r == 0); + *closed = 1; + *progress = 1; + return 0; + + case SSL_ERROR_WANT_WRITE: + *write_select = 1; + return 0; + + case SSL_ERROR_WANT_READ: + *read_select = 1; + return 0; + } + + return -1; +} + +static int +tls_connect_attempt(SSL *ssl, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref) +{ + int n, r; + + DEBUG_MSG("tls_connect_attempt"); + n = SSL_connect(ssl); + DEBUG_MSG2("SSL_connect",n); + r = tls_get_error(ssl, n, write_select, read_select, closed, progress); + if (r == -1) + *err_pref = " during SSL_connect"; + return r; +} + +static int +tls_accept_attempt(SSL *ssl, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref) +{ + int n, r; + + DEBUG_MSG("tls_accept_attempt"); + n = SSL_accept(ssl); + DEBUG_MSG2("SSL_accept",n); + r = tls_get_error(ssl, n, write_select, read_select, closed, progress); + if (r == -1) + *err_pref = " during SSL_accept"; + return r; +} + +static int +tls_write_attempt(SSL *ssl, struct tunnelbuf *buf, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref) +{ + int n, r; + + DEBUG_MSG("tls_write_attempt"); + n = SSL_write(ssl, buf->buf + buf->offset, buf->len); + DEBUG_MSG2("SSL_write",n); + r = tls_get_error(ssl, n, write_select, read_select, closed, progress); + if (n > 0) { + buf->len -= n; + assert(buf->len >= 0); + if (buf->len == 0) + buf->offset = 0; + else + buf->offset += n; + } + if (r == -1) + *err_pref = " during SSL_write"; + return r; +} + +static int +tls_read_attempt(SSL *ssl, struct tunnelbuf *buf, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref) +{ + int n, r; + size_t total; + + DEBUG_MSG("tls_read_attempt"); + total = buf->offset + buf->len; + assert(total < sizeof buf->buf); + n = SSL_read(ssl, buf->buf + total, (sizeof buf->buf) - total); + DEBUG_MSG2("SSL_read",n); + r = tls_get_error(ssl, n, write_select, read_select, closed, progress); + if (n > 0) { + buf->len += n; + assert(buf->offset + buf->len <= sizeof buf->buf); + } + if (r == -1) + *err_pref = " during SSL_read"; + return r; +} + +static int +get_error(int r, int *select, int *closed, int *progress) +{ + if (r >= 0) { + *progress = 1; + if (r == 0) + *closed = 1; + return 0; + } else { + assert(r == -1); + if (errno == EAGAIN || errno == EWOULDBLOCK) { + *select = 1; + return 0; + } else if (errno == EPIPE) { + *progress = 1; + *closed = 1; + return 0; + } else + return -1; + } +} + +static int write_attempt(int fd, struct tunnelbuf *buf, int *select, int *closed, int *progress) +{ + int n, r; + + DEBUG_MSG("write_attempt"); + n = write(fd, buf->buf + buf->offset, buf->len); + DEBUG_MSG2("write",n); + r = get_error(n, select, closed, progress); + if (n > 0) { + buf->len -= n; + assert(buf->len >= 0); + if (buf->len == 0) + buf->offset = 0; + else + buf->offset += n; + } + if (r == -1) + tls_errprintf(1, tls_child_apparg, "write error: %s\n", strerror(errno)); + return r; +} + +static int +read_attempt(int fd, struct tunnelbuf *buf, int *select, int *closed, int *progress) +{ + int n, r; + size_t total; + + DEBUG_MSG("read_attempt"); + total = buf->offset + buf->len; + assert(total < sizeof buf->buf); + n = read(fd, buf->buf + total, (sizeof buf->buf) - total); + DEBUG_MSG2("read",n); + r = get_error(n, select, closed, progress); + if (n > 0) { + buf->len += n; + assert(buf->offset + buf->len <= sizeof buf->buf); + } + if (r == -1) + tls_errprintf(1, tls_child_apparg, "read error: %s\n", strerror(errno)); + return r; +} diff --git a/demos/easy_tls/easy-tls.h b/demos/easy_tls/easy-tls.h new file mode 100644 index 0000000..52b298e --- /dev/null +++ b/demos/easy_tls/easy-tls.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ +/* + * easy-tls.h -- generic TLS proxy. + * $Id: easy-tls.h,v 1.1 2001/09/17 19:06:59 bodo Exp $ + */ +/* + * (c) Copyright 1999 Bodo Moeller. All rights reserved. + */ + +#ifndef HEADER_TLS_H +#define HEADER_TLS_H + +#ifndef HEADER_SSL_H +typedef struct ssl_ctx_st SSL_CTX; +#endif + +#define TLS_INFO_SIZE 512 /* max. # of bytes written to infofd */ + +void tls_set_dhe1024(int i, void* apparg); +/* Generate DHE parameters: + * i >= 0 deterministic (i selects seed), i < 0 random (may take a while). + * tls_create_ctx calls this with random non-negative i if the application + * has never called it.*/ + +void tls_rand_seed(void); +int tls_rand_seed_from_file(const char *filename, size_t n, void *apparg); +void tls_rand_seed_from_memory(const void *buf, size_t n); + +struct tls_create_ctx_args +{ + int client_p; + const char *certificate_file; + const char *key_file; + const char *ca_file; + int verify_depth; + int fail_unless_verified; + int export_p; +}; +struct tls_create_ctx_args tls_create_ctx_defaultargs(void); +/* struct tls_create_ctx_args is similar to a conventional argument list, + * but it can provide default values and allows for future extension. */ +SSL_CTX *tls_create_ctx(struct tls_create_ctx_args, void *apparg); + +struct tls_start_proxy_args +{ + int fd; + int client_p; + SSL_CTX *ctx; + pid_t *pid; + int *infofd; +}; +struct tls_start_proxy_args tls_start_proxy_defaultargs(void); +/* tls_start_proxy return value *MUST* be checked! + * 0 means ok, otherwise we've probably run out of some resources. */ +int tls_start_proxy(struct tls_start_proxy_args, void *apparg); + +#endif diff --git a/demos/easy_tls/test.c b/demos/easy_tls/test.c new file mode 100644 index 0000000..21f679a --- /dev/null +++ b/demos/easy_tls/test.c @@ -0,0 +1,244 @@ +/* test.c */ +/* $Id: test.c,v 1.1 2001/09/17 19:06:59 bodo Exp $ */ + +#define L_PORT 9999 +#define C_PORT 443 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" +#include "easy-tls.h" + +void +test_process_init(int fd, int client_p, void *apparg) +{ + fprintf(stderr, "test_process_init(fd = %d, client_p = %d, apparg = %p)\n", fd, client_p, apparg); +} + +void +test_errflush(int child_p, char *errbuf, size_t num, void *apparg) +{ + fputs(errbuf, stderr); +} + + +int +main(int argc, char *argv[]) +{ + int s, fd, r; + FILE *conn_in; + FILE *conn_out; + char buf[256]; + SSL_CTX *ctx; + int client_p = 0; + int port; + int tls = 0; + char infobuf[TLS_INFO_SIZE + 1]; + + if (argc > 1 && argv[1][0] == '-') { + fputs("Usage: test [port] -- server\n" + " test num.num.num.num [port] -- client\n", + stderr); + exit(1); + } + + if (argc > 1) { + if (strchr(argv[1], '.')) { + client_p = 1; + } + } + + fputs(client_p ? "Client\n" : "Server\n", stderr); + + { + struct tls_create_ctx_args a = tls_create_ctx_defaultargs(); + a.client_p = client_p; + a.certificate_file = "cert.pem"; + a.key_file = "cert.pem"; + a.ca_file = "cacerts.pem"; + + ctx = tls_create_ctx(a, NULL); + if (ctx == NULL) + exit(1); + } + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s == -1) { + perror("socket"); + exit(1); + } + + if (client_p) { + struct sockaddr_in addr; + size_t addr_len = sizeof addr; + + addr.sin_family = AF_INET; + assert(argc > 1); + if (argc > 2) + sscanf(argv[2], "%d", &port); + else + port = C_PORT; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = inet_addr(argv[1]); + + r = connect(s, &addr, addr_len); + if (r != 0) { + perror("connect"); + exit(1); + } + fd = s; + fprintf(stderr, "Connect (fd = %d).\n", fd); + } else { + /* server */ + { + int i = 1; + + r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof i); + if (r == -1) { + perror("setsockopt"); + exit(1); + } + } + + { + struct sockaddr_in addr; + size_t addr_len = sizeof addr; + + if (argc > 1) + sscanf(argv[1], "%d", &port); + else + port = L_PORT; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + r = bind(s, &addr, addr_len); + if (r != 0) { + perror("bind"); + exit(1); + } + } + + r = listen(s, 1); + if (r == -1) { + perror("listen"); + exit(1); + } + + fprintf(stderr, "Listening at port %i.\n", port); + + fd = accept(s, NULL, 0); + if (fd == -1) { + perror("accept"); + exit(1); + } + + fprintf(stderr, "Accept (fd = %d).\n", fd); + } + + conn_in = fdopen(fd, "r"); + if (conn_in == NULL) { + perror("fdopen"); + exit(1); + } + conn_out = fdopen(fd, "w"); + if (conn_out == NULL) { + perror("fdopen"); + exit(1); + } + + setvbuf(conn_in, NULL, _IOLBF, 256); + setvbuf(conn_out, NULL, _IOLBF, 256); + + while (fgets(buf, sizeof buf, stdin) != NULL) { + if (buf[0] == 'W') { + fprintf(conn_out, "%.*s\r\n", (int)(strlen(buf + 1) - 1), buf + 1); + fprintf(stderr, ">>> %.*s\n", (int)(strlen(buf + 1) - 1), buf + 1); + } else if (buf[0] == 'C') { + fprintf(stderr, "Closing.\n"); + fclose(conn_in); + fclose(conn_out); + exit(0); + } else if (buf[0] == 'R') { + int lines = 0; + + sscanf(buf + 1, "%d", &lines); + do { + if (fgets(buf, sizeof buf, conn_in) == NULL) { + if (ferror(conn_in)) { + fprintf(stderr, "ERROR\n"); + exit(1); + } + fprintf(stderr, "CLOSED\n"); + return 0; + } + fprintf(stderr, "<<< %s", buf); + } while (--lines > 0); + } else if (buf[0] == 'T') { + int infofd; + + tls++; + { + struct tls_start_proxy_args a = tls_start_proxy_defaultargs(); + a.fd = fd; + a.client_p = client_p; + a.ctx = ctx; + a.infofd = &infofd; + r = tls_start_proxy(a, NULL); + } + assert(r != 1); + if (r != 0) { + fprintf(stderr, "tls_start_proxy failed: %d\n", r); + switch (r) { + case -1: + fputs("socketpair", stderr); break; + case 2: + fputs("FD_SETSIZE exceeded", stderr); break; + case -3: + fputs("pipe", stderr); break; + case -4: + fputs("fork", stderr); break; + case -5: + fputs("dup2", stderr); break; + default: + fputs("?", stderr); + } + if (r < 0) + perror(""); + else + fputc('\n', stderr); + exit(1); + } + + r = read(infofd, infobuf, sizeof infobuf - 1); + if (r > 0) { + const char *info = infobuf; + const char *eol; + + infobuf[r] = '\0'; + while ((eol = strchr(info, '\n')) != NULL) { + fprintf(stderr, "+++ `%.*s'\n", eol - info, info); + info = eol+1; + } + close (infofd); + } + } else { + fprintf(stderr, "W... write line to network\n" + "R[n] read line (n lines) from network\n" + "C close\n" + "T start %sTLS proxy\n", tls ? "another " : ""); + } + } + return 0; +} diff --git a/demos/easy_tls/test.h b/demos/easy_tls/test.h new file mode 100644 index 0000000..dda6678 --- /dev/null +++ b/demos/easy_tls/test.h @@ -0,0 +1,11 @@ +/* test.h */ +/* $Id: test.h,v 1.1 2001/09/17 19:07:00 bodo Exp $ */ + + +void test_process_init(int fd, int client_p, void *apparg); +#define TLS_APP_PROCESS_INIT test_process_init + +#undef TLS_CUMULATE_ERRORS + +void test_errflush(int child_p, char *errbuf, size_t num, void *apparg); +#define TLS_APP_ERRFLUSH test_errflush diff --git a/demos/eay/Makefile b/demos/eay/Makefile new file mode 100644 index 0000000..2d22eac --- /dev/null +++ b/demos/eay/Makefile @@ -0,0 +1,24 @@ +CC=cc +CFLAGS= -g -I../../include +#LIBS= -L../.. -lcrypto -lssl +LIBS= -L../.. ../../libssl.a ../../libcrypto.a + +# the file conn.c requires a file "proxy.h" which I couldn't find... +#EXAMPLES=base64 conn loadrsa +EXAMPLES=base64 loadrsa + +all: $(EXAMPLES) + +base64: base64.o + $(CC) -o base64 base64.o $(LIBS) +# +# sorry... can't find "proxy.h" +#conn: conn.o +# $(CC) -o conn conn.o $(LIBS) + +loadrsa: loadrsa.o + $(CC) -o loadrsa loadrsa.o $(LIBS) + +clean: + rm -f $(EXAMPLES) *.o + diff --git a/demos/eay/base64.c b/demos/eay/base64.c new file mode 100644 index 0000000..4b8b062 --- /dev/null +++ b/demos/eay/base64.c @@ -0,0 +1,49 @@ +/* This is a simple example of using the base64 BIO to a memory BIO and then + * getting the data. + */ +#include +#include +#include + +main() + { + int i; + BIO *mbio,*b64bio,*bio; + char buf[512]; + char *p; + + mbio=BIO_new(BIO_s_mem()); + b64bio=BIO_new(BIO_f_base64()); + + bio=BIO_push(b64bio,mbio); + /* We now have bio pointing at b64->mem, the base64 bio encodes on + * write and decodes on read */ + + for (;;) + { + i=fread(buf,1,512,stdin); + if (i <= 0) break; + BIO_write(bio,buf,i); + } + /* We need to 'flush' things to push out the encoding of the + * last few bytes. There is special encoding if it is not a + * multiple of 3 + */ + BIO_flush(bio); + + printf("We have %d bytes available\n",BIO_pending(mbio)); + + /* We will now get a pointer to the data and the number of elements. */ + /* hmm... this one was not defined by a macro in bio.h, it will be for + * 0.9.1. The other option is too just read from the memory bio. + */ + i=(int)BIO_ctrl(mbio,BIO_CTRL_INFO,0,(char *)&p); + + printf("%d\n",i); + fwrite("---\n",1,4,stdout); + fwrite(p,1,i,stdout); + fwrite("---\n",1,4,stdout); + + /* This call will walk the chain freeing all the BIOs */ + BIO_free_all(bio); + } diff --git a/demos/eay/conn.c b/demos/eay/conn.c new file mode 100644 index 0000000..c4b8f51 --- /dev/null +++ b/demos/eay/conn.c @@ -0,0 +1,105 @@ +/* NOCW */ +/* demos/eay/conn.c */ + +/* A minimal program to connect to a port using the sock4a protocol. + * + * cc -I../../include conn.c -L../.. -lcrypto + */ +#include +#include +#include +#include +/* #include "proxy.h" */ + +extern int errno; + +int main(argc,argv) +int argc; +char *argv[]; + { + PROXY *pxy; + char *host; + char buf[1024*10],*p; + BIO *bio; + int i,len,off,ret=1; + + if (argc <= 1) + host="localhost:4433"; + else + host=argv[1]; + + /* Lets get nice error messages */ + ERR_load_crypto_strings(); + + /* First, configure proxy settings */ + pxy=PROXY_new(); + PROXY_add_server(pxy,PROXY_PROTOCOL_SOCKS,"gromit:1080"); + + bio=BIO_new(BIO_s_socks4a_connect()); + + BIO_set_conn_hostname(bio,host); + BIO_set_proxies(bio,pxy); + BIO_set_socks_userid(bio,"eay"); + BIO_set_nbio(bio,1); + + p="GET / HTTP/1.0\r\n\r\n"; + len=strlen(p); + + off=0; + for (;;) + { + i=BIO_write(bio,&(p[off]),len); + if (i <= 0) + { + if (BIO_should_retry(bio)) + { + fprintf(stderr,"write DELAY\n"); + sleep(1); + continue; + } + else + { + goto err; + } + } + off+=i; + len-=i; + if (len <= 0) break; + } + + for (;;) + { + i=BIO_read(bio,buf,sizeof(buf)); + if (i == 0) break; + if (i < 0) + { + if (BIO_should_retry(bio)) + { + fprintf(stderr,"read DELAY\n"); + sleep(1); + continue; + } + goto err; + } + fwrite(buf,1,i,stdout); + } + + ret=1; + + if (0) + { +err: + if (ERR_peek_error() == 0) /* system call error */ + { + fprintf(stderr,"errno=%d ",errno); + perror("error"); + } + else + ERR_print_errors_fp(stderr); + } + BIO_free_all(bio); + if (pxy != NULL) PROXY_free(pxy); + exit(!ret); + return(ret); + } + diff --git a/demos/eay/loadrsa.c b/demos/eay/loadrsa.c new file mode 100644 index 0000000..79f1885 --- /dev/null +++ b/demos/eay/loadrsa.c @@ -0,0 +1,53 @@ +#include +#include + +/* This is a simple program to generate an RSA private key. It then + * saves both the public and private key into a char array, then + * re-reads them. It saves them as DER encoded binary data. + */ + +void callback(stage,count,arg) +int stage,count; +char *arg; + { + FILE *out; + + out=(FILE *)arg; + fprintf(out,"%d",stage); + if (stage == 3) + fprintf(out,"\n"); + fflush(out); + } + +main() + { + RSA *rsa,*pub_rsa,*priv_rsa; + int len; + unsigned char buf[1024],*p; + + rsa=RSA_generate_key(512,RSA_F4,callback,(char *)stdout); + + p=buf; + + /* Save the public key into buffer, we know it will be big enough + * but we should really check how much space we need by calling the + * i2d functions with a NULL second parameter */ + len=i2d_RSAPublicKey(rsa,&p); + len+=i2d_RSAPrivateKey(rsa,&p); + + printf("The public and private key are now both in a char array\n"); + printf("and are taking up %d bytes\n",len); + + RSA_free(rsa); + + p=buf; + pub_rsa=d2i_RSAPublicKey(NULL,&p,(long)len); + len-=(p-buf); + priv_rsa=d2i_RSAPrivateKey(NULL,&p,(long)len); + + if ((pub_rsa == NULL) || (priv_rsa == NULL)) + ERR_print_errors_fp(stderr); + + RSA_free(pub_rsa); + RSA_free(priv_rsa); + } diff --git a/demos/engines/cluster_labs/Makefile b/demos/engines/cluster_labs/Makefile new file mode 100644 index 0000000..956193f --- /dev/null +++ b/demos/engines/cluster_labs/Makefile @@ -0,0 +1,114 @@ +LIBNAME= libclabs +SRC= hw_cluster_labs.c +OBJ= hw_cluster_labs.o +HEADER= hw_cluster_labs.h + +CC= gcc +PIC= -fPIC +CFLAGS= -g -I../../../include $(PIC) -DENGINE_DYNAMIC_SUPPORT -DFLAT_INC +AR= ar r +RANLIB= ranlib + +LIB= $(LIBNAME).a +SHLIB= $(LIBNAME).so + +all: + @echo 'Please choose a system to build on:' + @echo '' + @echo 'tru64: Tru64 Unix, Digital Unix, Digital OSF/1' + @echo 'solaris: Solaris' + @echo 'irix: IRIX' + @echo 'hpux32: 32-bit HP/UX' + @echo 'hpux64: 64-bit HP/UX' + @echo 'aix: AIX' + @echo 'gnu: Generic GNU-based system (gcc and GNU ld)' + @echo '' + +FORCE.update: +update: FORCE.update + perl ../../../util/mkerr.pl -conf hw_cluster_labs.ec \ + -nostatic -staticloader -write hw_cluster_labs.c + +gnu: $(SHLIB).gnu +tru64: $(SHLIB).tru64 +solaris: $(SHLIB).solaris +irix: $(SHLIB).irix +hpux32: $(SHLIB).hpux32 +hpux64: $(SHLIB).hpux64 +aix: $(SHLIB).aix + +$(LIB): $(OBJ) + $(AR) $(LIB) $(OBJ) + - $(RANLIB) $(LIB) + +LINK_SO= \ + ld -r -o $(LIBNAME).o $$ALLSYMSFLAGS $(LIB) && \ + (nm -Pg $(LIBNAME).o | grep ' [BDT] ' | cut -f1 -d' ' > $(LIBNAME).exp; \ + $$SHAREDCMD $$SHAREDFLAGS -o $(SHLIB) $(LIBNAME).o -L ../../.. -lcrypto -lc) + +$(SHLIB).gnu: $(LIB) + ALLSYMSFLAGS='--whole-archive' \ + SHAREDFLAGS='-shared -Wl,-soname=$(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).gnu +$(SHLIB).tru64: $(LIB) + ALLSYMSFLAGS='-all' \ + SHAREDFLAGS='-shared' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).tru64 +$(SHLIB).solaris: $(LIB) + ALLSYMSFLAGS='-z allextract' \ + SHAREDFLAGS='-G -h $(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).solaris +$(SHLIB).irix: $(LIB) + ALLSYMSFLAGS='-all' \ + SHAREDFLAGS='-shared -Wl,-soname,$(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).irix +$(SHLIB).hpux32: $(LIB) + ALLSYMSFLAGS='-Fl' \ + SHAREDFLAGS='+vnocompatwarnings -b -z +s +h $(SHLIB)' \ + SHAREDCMD='/usr/ccs/bin/ld'; \ + $(LINK_SO) + touch $(SHLIB).hpux32 +$(SHLIB).hpux64: $(LIB) + ALLSYMSFLAGS='+forceload' \ + SHAREDFLAGS='-b -z +h $(SHLIB)' \ + SHAREDCMD='/usr/ccs/bin/ld'; \ + $(LINK_SO) + touch $(SHLIB).hpux64 +$(SHLIB).aix: $(LIB) + ALLSYMSFLAGS='-bnogc' \ + SHAREDFLAGS='-G -bE:$(LIBNAME).exp -bM:SRE' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).aix + +depend: + sed -e '/^# DO NOT DELETE.*/,$$d' < Makefile > Makefile.tmp + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' >> Makefile.tmp + gcc -M $(CFLAGS) $(SRC) >> Makefile.tmp + perl ../../../util/clean-depend.pl < Makefile.tmp > Makefile.new + rm -f Makefile.tmp Makefile + mv Makefile.new Makefile + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +rsaref.o: ../../../include/openssl/asn1.h ../../../include/openssl/bio.h +rsaref.o: ../../../include/openssl/bn.h ../../../include/openssl/crypto.h +rsaref.o: ../../../include/openssl/dh.h ../../../include/openssl/dsa.h +rsaref.o: ../../../include/openssl/e_os2.h ../../../include/openssl/engine.h +rsaref.o: ../../../include/openssl/err.h ../../../include/openssl/lhash.h +rsaref.o: ../../../include/openssl/opensslconf.h +rsaref.o: ../../../include/openssl/opensslv.h +rsaref.o: ../../../include/openssl/ossl_typ.h ../../../include/openssl/rand.h +rsaref.o: ../../../include/openssl/rsa.h ../../../include/openssl/safestack.h +rsaref.o: ../../../include/openssl/stack.h ../../../include/openssl/symhacks.h +rsaref.o: ../../../include/openssl/ui.h rsaref.c rsaref_err.c rsaref_err.h +rsaref.o: source/des.h source/global.h source/md2.h source/md5.h source/rsa.h +rsaref.o: source/rsaref.h diff --git a/demos/engines/cluster_labs/cluster_labs.h b/demos/engines/cluster_labs/cluster_labs.h new file mode 100644 index 0000000..d092679 --- /dev/null +++ b/demos/engines/cluster_labs/cluster_labs.h @@ -0,0 +1,35 @@ +typedef int cl_engine_init(void); +typedef int cl_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *cgx); +typedef int cl_mod_exp_crt(BIGNUM *r, BIGNUM *a, const BIGNUM *p, + const BIGNUM *q, const BIGNUM *dmp1, const BIGNUM *dmq1, + const BIGNUM *iqmp, BN_CTX *ctx); +typedef int cl_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa); +typedef int cl_rsa_pub_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +typedef int cl_rsa_pub_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +typedef int cl_rsa_priv_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +typedef int cl_rsa_priv_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +typedef int cl_rand_bytes(unsigned char *buf, int num); +typedef DSA_SIG *cl_dsa_sign(const unsigned char *dgst, int dlen, DSA *dsa); +typedef int cl_dsa_verify(const unsigned char *dgst, int dgst_len, + DSA_SIG *sig, DSA *dsa); + + +static const char *CLUSTER_LABS_LIB_NAME = "cluster_labs"; +static const char *CLUSTER_LABS_F1 = "hw_engine_init"; +static const char *CLUSTER_LABS_F2 = "hw_mod_exp"; +static const char *CLUSTER_LABS_F3 = "hw_mod_exp_crt"; +static const char *CLUSTER_LABS_F4 = "hw_rsa_mod_exp"; +static const char *CLUSTER_LABS_F5 = "hw_rsa_priv_enc"; +static const char *CLUSTER_LABS_F6 = "hw_rsa_priv_dec"; +static const char *CLUSTER_LABS_F7 = "hw_rsa_pub_enc"; +static const char *CLUSTER_LABS_F8 = "hw_rsa_pub_dec"; +static const char *CLUSTER_LABS_F20 = "hw_rand_bytes"; +static const char *CLUSTER_LABS_F30 = "hw_dsa_sign"; +static const char *CLUSTER_LABS_F31 = "hw_dsa_verify"; + + diff --git a/demos/engines/cluster_labs/hw_cluster_labs.c b/demos/engines/cluster_labs/hw_cluster_labs.c new file mode 100644 index 0000000..036f48b --- /dev/null +++ b/demos/engines/cluster_labs/hw_cluster_labs.c @@ -0,0 +1,721 @@ +/* crypto/engine/hw_cluster_labs.c */ +/* Written by Jan Tschirschwitz (jan.tschirschwitz@cluster-labs.com + * for the OpenSSL project 2000. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#define MSC_VER /* only used cryptic.h */ + +#include +#include +#include +#include +#include + +#ifndef NO_HW +#ifndef NO_HW_CLUSTER_LABS + +#ifdef FLAT_INC +#include "cluster_labs.h" +#else +#include "vendor_defns/cluster_labs.h" +#endif + +#define CL_LIB_NAME "cluster_labs engine" +#include "hw_cluster_labs_err.c" + + +static int cluster_labs_destroy(ENGINE *e); +static int cluster_labs_init(ENGINE *e); +static int cluster_labs_finish(ENGINE *e); +static int cluster_labs_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()); + + +/* BIGNUM stuff */ +/* This function is aliased to mod_exp (with the mont stuff dropped). */ +static int cluster_labs_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); + +/* RSA stuff */ +#ifndef OPENSSL_NO_RSA +static int cluster_labs_rsa_pub_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +static int cluster_labs_rsa_pub_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +static int cluster_labs_rsa_priv_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +static int cluster_labs_rsa_priv_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +static int cluster_labs_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa); +#endif + +/* DSA stuff */ +#ifndef OPENSSL_NO_DSA +static DSA_SIG *cluster_labs_dsa_sign(const unsigned char *dgst, int dlen, DSA *dsa); +static int cluster_labs_dsa_verify(const unsigned char *dgst, int dgst_len, + DSA_SIG *sig, DSA *dsa); +static int cluster_labs_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, + BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *in_mont); +static int cluster_labs_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); +#endif + +/* DH stuff */ +#ifndef OPENSSL_NO_DH +/* This function is alised to mod_exp (with the DH and mont dropped). */ +static int cluster_labs_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +#endif + +/* RANDOM stuff */ +static int cluster_labs_rand_bytes(unsigned char *buf, int num); + +/* The definitions for control commands specific to this engine */ +#define CLUSTER_LABS_CMD_SO_PATH ENGINE_CMD_BASE +static const ENGINE_CMD_DEFN cluster_labs_cmd_defns[] = + { + { CLUSTER_LABS_CMD_SO_PATH, + "SO_PATH", + "Specifies the path to the 'cluster labs' shared library", + ENGINE_CMD_FLAG_STRING + }, + {0, NULL, NULL, 0} + }; + +/* Our internal RSA_METHOD that we provide pointers to */ +#ifndef OPENSSL_NO_RSA +static RSA_METHOD cluster_labs_rsa = + { + "Cluster Labs RSA method", + cluster_labs_rsa_pub_enc, /* rsa_pub_enc */ + cluster_labs_rsa_pub_dec, /* rsa_pub_dec */ + cluster_labs_rsa_priv_enc, /* rsa_priv_enc */ + cluster_labs_rsa_priv_dec, /* rsa_priv_dec */ + cluster_labs_rsa_mod_exp, /* rsa_mod_exp */ + cluster_labs_mod_exp_mont, /* bn_mod_exp */ + NULL, /* init */ + NULL, /* finish */ + 0, /* flags */ + NULL, /* apps_data */ + NULL, /* rsa_sign */ + NULL /* rsa_verify */ + }; +#endif + +/* Our internal DSA_METHOD that we provide pointers to */ +#ifndef OPENSSL_NO_DSA +static DSA_METHOD cluster_labs_dsa = + { + "Cluster Labs DSA method", + cluster_labs_dsa_sign, /* dsa_do_sign */ + NULL, /* dsa_sign_setup */ + cluster_labs_dsa_verify, /* dsa_do_verify */ + cluster_labs_dsa_mod_exp, /* dsa_mod_exp */ + cluster_labs_mod_exp_dsa, /* bn_mod_exp */ + NULL, /* init */ + NULL, /* finish */ + 0, /* flags */ + NULL /* app_data */ + }; +#endif + +/* Our internal DH_METHOD that we provide pointers to */ +#ifndef OPENSSL_NO_DH +static DH_METHOD cluster_labs_dh = + { + "Cluster Labs DH method", + NULL, /* generate key */ + NULL, /* compute key */ + cluster_labs_mod_exp_dh, /* bn_mod_exp */ + NULL, /* init */ + NULL, /* finish */ + 0, /* flags */ + NULL /* app_data */ + }; +#endif + +static RAND_METHOD cluster_labs_rand = + { + /* "Cluster Labs RAND method", */ + NULL, /* seed */ + cluster_labs_rand_bytes, /* bytes */ + NULL, /* cleanup */ + NULL, /* add */ + cluster_labs_rand_bytes, /* pseudorand */ + NULL, /* status */ + }; + +static const char *engine_cluster_labs_id = "cluster_labs"; +static const char *engine_cluster_labs_name = "Cluster Labs hardware engine support"; + +/* engine implementation */ +/*-----------------------*/ +static int bind_helper(ENGINE *e) + { + + if(!ENGINE_set_id(e, engine_cluster_labs_id) || + !ENGINE_set_name(e, engine_cluster_labs_name) || +#ifndef OPENSSL_NO_RSA + !ENGINE_set_RSA(e, &cluster_labs_rsa) || +#endif +#ifndef OPENSSL_NO_DSA + !ENGINE_set_DSA(e, &cluster_labs_dsa) || +#endif +#ifndef OPENSSL_NO_DH + !ENGINE_set_DH(e, &cluster_labs_dh) || +#endif + !ENGINE_set_RAND(e, &cluster_labs_rand) || + !ENGINE_set_destroy_function(e, cluster_labs_destroy) || + !ENGINE_set_init_function(e, cluster_labs_init) || + !ENGINE_set_finish_function(e, cluster_labs_finish) || + !ENGINE_set_ctrl_function(e, cluster_labs_ctrl) || + !ENGINE_set_cmd_defns(e, cluster_labs_cmd_defns)) + return 0; + /* Ensure the error handling is set up */ + ERR_load_CL_strings(); + return 1; + } + +#ifndef ENGINE_DYNAMIC_SUPPORT +static ENGINE *engine_cluster_labs(void) + { + ENGINE *ret = ENGINE_new(); + + if(!ret) + return NULL; + if(!bind_helper(ret)) + { + ENGINE_free(ret); + return NULL; + } + return ret; + } + +#ifdef ENGINE_DYNAMIC_SUPPORT +static +#endif +void ENGINE_load_cluster_labs(void) + { + + ENGINE *cluster_labs = engine_cluster_labs(); + + if(!cluster_labs) return; + ENGINE_add(cluster_labs); + ENGINE_free(cluster_labs); + ERR_clear_error(); + } +#endif /* !ENGINE_DYNAMIC_SUPPORT */ + +static int cluster_labs_destroy(ENGINE *e) + { + + ERR_unload_CL_strings(); + return 1; + } + + + +/* This is a process-global DSO handle used for loading and unloading + * the Cluster Labs library. NB: This is only set (or unset) during an + * init() or finish() call (reference counts permitting) and they're + * operating with global locks, so this should be thread-safe + * implicitly. */ +static DSO *cluster_labs_dso = NULL; + +/* These are the function pointers that are (un)set when the library has + * successfully (un)loaded. */ +static cl_engine_init *p_cl_engine_init = NULL; +static cl_mod_exp *p_cl_mod_exp = NULL; +static cl_mod_exp_crt *p_cl_mod_exp_crt = NULL; +static cl_rsa_mod_exp *p_cl_rsa_mod_exp = NULL; +static cl_rsa_priv_enc *p_cl_rsa_priv_enc = NULL; +static cl_rsa_priv_dec *p_cl_rsa_priv_dec = NULL; +static cl_rsa_pub_enc *p_cl_rsa_pub_enc = NULL; +static cl_rsa_pub_dec *p_cl_rsa_pub_dec = NULL; +static cl_rand_bytes *p_cl_rand_bytes = NULL; +static cl_dsa_sign *p_cl_dsa_sign = NULL; +static cl_dsa_verify *p_cl_dsa_verify = NULL; + + +int cluster_labs_init(ENGINE *e) + { + + cl_engine_init *p1; + cl_mod_exp *p2; + cl_mod_exp_crt *p3; + cl_rsa_mod_exp *p4; + cl_rsa_priv_enc *p5; + cl_rsa_priv_dec *p6; + cl_rsa_pub_enc *p7; + cl_rsa_pub_dec *p8; + cl_rand_bytes *p20; + cl_dsa_sign *p30; + cl_dsa_verify *p31; + + /* engine already loaded */ + if(cluster_labs_dso != NULL) + { + CLerr(CL_F_CLUSTER_LABS_INIT,CL_R_ALREADY_LOADED); + goto err; + } + /* try to load engine */ + cluster_labs_dso = DSO_load(NULL, CLUSTER_LABS_LIB_NAME, NULL,0); + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_INIT,CL_R_DSO_FAILURE); + goto err; + } + /* bind functions */ + if( !(p1 = (cl_engine_init *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F1)) || + !(p2 = (cl_mod_exp *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F2)) || + !(p3 = (cl_mod_exp_crt *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F3)) || + !(p4 = (cl_rsa_mod_exp *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F4)) || + !(p5 = (cl_rsa_priv_enc *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F5)) || + !(p6 = (cl_rsa_priv_dec *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F6)) || + !(p7 = (cl_rsa_pub_enc *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F7)) || + !(p8 = (cl_rsa_pub_dec *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F8)) || + !(p20= (cl_rand_bytes *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F20)) || + !(p30= (cl_dsa_sign *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F30)) || + !(p31= (cl_dsa_verify *)DSO_bind_func( + cluster_labs_dso, CLUSTER_LABS_F31))) + { + CLerr(CL_F_CLUSTER_LABS_INIT,CL_R_DSO_FAILURE); + goto err; + } + + /* copy function pointers */ + p_cl_engine_init = p1; + p_cl_mod_exp = p2; + p_cl_mod_exp_crt = p3; + p_cl_rsa_mod_exp = p4; + p_cl_rsa_priv_enc = p5; + p_cl_rsa_priv_dec = p6; + p_cl_rsa_pub_enc = p7; + p_cl_rsa_pub_dec = p8; + p_cl_rand_bytes = p20; + p_cl_dsa_sign = p30; + p_cl_dsa_verify = p31; + + + + /* cluster labs engine init */ + if(p_cl_engine_init()== 0){ + CLerr(CL_F_CLUSTER_LABS_INIT,CL_R_INIT_FAILED); + goto err; + } + + return(1); + +err: + /* reset all pointers */ + if(cluster_labs_dso) + DSO_free(cluster_labs_dso); + + cluster_labs_dso = NULL; + p_cl_engine_init = NULL; + p_cl_mod_exp = NULL; + p_cl_mod_exp_crt = NULL; + p_cl_rsa_mod_exp = NULL; + p_cl_rsa_priv_enc = NULL; + p_cl_rsa_priv_dec = NULL; + p_cl_rsa_pub_enc = NULL; + p_cl_rsa_pub_dec = NULL; + p_cl_rand_bytes = NULL; + p_cl_dsa_sign = NULL; + p_cl_dsa_verify = NULL; + + return(0); + } + + +static int cluster_labs_finish(ENGINE *e) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_FINISH,CL_R_NOT_LOADED); + return 0; + } + if(!DSO_free(cluster_labs_dso)) + { + CLerr(CL_F_CLUSTER_LABS_FINISH,CL_R_DSO_FAILURE); + return 0; + } + + cluster_labs_dso = NULL; + p_cl_engine_init = NULL; + p_cl_mod_exp = NULL; + p_cl_rsa_mod_exp = NULL; + p_cl_mod_exp_crt = NULL; + p_cl_rsa_priv_enc = NULL; + p_cl_rsa_priv_dec = NULL; + p_cl_rsa_pub_enc = NULL; + p_cl_rsa_pub_dec = NULL; + p_cl_rand_bytes = NULL; + p_cl_dsa_sign = NULL; + p_cl_dsa_verify = NULL; + + return(1); + + } + +static int cluster_labs_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()) + { + int initialised = ((cluster_labs_dso == NULL) ? 0 : 1); + + switch(cmd) + { + case CLUSTER_LABS_CMD_SO_PATH: + if(p == NULL) + { + CLerr(CL_F_CLUSTER_LABS_CTRL,ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if(initialised) + { + CLerr(CL_F_CLUSTER_LABS_CTRL,CL_R_ALREADY_LOADED); + return 0; + } + CLUSTER_LABS_LIB_NAME = (const char *)p; + return 1; + default: + break; + } + CLerr(CL_F_CLUSTER_LABS_CTRL,CL_R_COMMAND_NOT_IMPLEMENTED); + return 0; + } + + +static int cluster_labs_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_MOD_EXP,CL_R_NOT_LOADED); + return 0; + } + if(p_cl_mod_exp == NULL) + { + CLerr(CL_F_CLUSTER_LABS_MOD_EXP,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_mod_exp(r, a, p, m, ctx); + + } + +static int cluster_labs_mod_exp_crt(BIGNUM *r, BIGNUM *a, const BIGNUM *p, + const BIGNUM *q, const BIGNUM *dmp1, const BIGNUM *dmq1, + const BIGNUM *iqmp, BN_CTX *ctx) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_MOD_EXP_CRT,CL_R_NOT_LOADED); + return 0; + } + if(p_cl_mod_exp_crt == NULL) + { + CLerr(CL_F_CLUSTER_LABS_MOD_EXP_CRT,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_mod_exp_crt(r, a, p, q,dmp1, dmq1, iqmp, ctx); + + } + +static int cluster_labs_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_MOD_EXP,CL_R_NOT_LOADED); + return 0; + } + if(p_cl_rsa_mod_exp == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_MOD_EXP,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_rsa_mod_exp(r0, I, rsa); + + } + +static DSA_SIG *cluster_labs_dsa_sign(const unsigned char *dgst, int dlen, DSA *dsa) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_DSA_SIGN,CL_R_NOT_LOADED); + return 0; + } + if(p_cl_dsa_sign == NULL) + { + CLerr(CL_F_CLUSTER_LABS_DSA_SIGN,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_dsa_sign(dgst, dlen, dsa); + + } + +static int cluster_labs_dsa_verify(const unsigned char *dgst, int dgst_len, + DSA_SIG *sig, DSA *dsa) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_DSA_VERIFY,CL_R_NOT_LOADED); + return 0; + } + + if(p_cl_dsa_verify == NULL) + { + CLerr(CL_F_CLUSTER_LABS_DSA_VERIFY,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_dsa_verify(dgst, dgst_len, sig, dsa); + + } + +static int cluster_labs_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, + BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *in_mont) + { + BIGNUM t; + int status = 0; + + BN_init(&t); + /* let rr = a1 ^ p1 mod m */ + if (!cluster_labs_mod_exp(rr,a1,p1,m,ctx)) goto end; + /* let t = a2 ^ p2 mod m */ + if (!cluster_labs_mod_exp(&t,a2,p2,m,ctx)) goto end; + /* let rr = rr * t mod m */ + if (!BN_mod_mul(rr,rr,&t,m,ctx)) goto end; + status = 1; +end: + BN_free(&t); + + return(1); + + } + +static int cluster_labs_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx) + { + return cluster_labs_mod_exp(r, a, p, m, ctx); + } + +/* This function is aliased to mod_exp (with the mont stuff dropped). */ +static int cluster_labs_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) + { + return cluster_labs_mod_exp(r, a, p, m, ctx); + } + + +/* This function is aliased to mod_exp (with the dh and mont dropped). */ +static int cluster_labs_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) + { + return cluster_labs_mod_exp(r, a, p, m, ctx); + } + + +static int cluster_labs_rsa_pub_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_PUB_ENC,CL_R_NOT_LOADED); + return 0; + } + if(p_cl_rsa_priv_enc == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_PUB_ENC,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_rsa_pub_enc(flen, from, to, rsa, padding); + + } + +static int cluster_labs_rsa_pub_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_PUB_DEC,CL_R_NOT_LOADED); + return 0; + } + if(p_cl_rsa_priv_enc == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_PUB_DEC,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_rsa_pub_dec(flen, from, to, rsa, padding); + + } + + +static int cluster_labs_rsa_priv_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_PRIV_ENC,CL_R_NOT_LOADED); + return 0; + } + + if(p_cl_rsa_priv_enc == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_PRIV_ENC,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_rsa_priv_enc(flen, from, to, rsa, padding); + + } + +static int cluster_labs_rsa_priv_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) + { + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_PRIV_DEC,CL_R_NOT_LOADED); + return 0; + } + if(p_cl_rsa_priv_dec == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RSA_PRIV_DEC,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_rsa_priv_dec(flen, from, to, rsa, padding); + + } + +/************************************************************************************ +* Symmetric algorithms +************************************************************************************/ +/* this will be come soon! */ + +/************************************************************************************ +* Random generator +************************************************************************************/ + +static int cluster_labs_rand_bytes(unsigned char *buf, int num){ + + if(cluster_labs_dso == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RAND_BYTES,CL_R_NOT_LOADED); + return 0; + } + if(p_cl_mod_exp_crt == NULL) + { + CLerr(CL_F_CLUSTER_LABS_RAND_BYTES,CL_R_FUNCTION_NOT_BINDED); + return 0; + } + + return p_cl_rand_bytes(buf, num); + +} + + +/* This stuff is needed if this ENGINE is being compiled into a self-contained + * shared-library. */ +#ifdef ENGINE_DYNAMIC_SUPPORT +static int bind_fn(ENGINE *e, const char *id) + { + fprintf(stderr, "bind_fn CLUSTER_LABS\n"); + if(id && (strcmp(id, engine_cluster_labs_id) != 0)) { + fprintf(stderr, "bind_fn return(0) first\n"); + return 0; + } + if(!bind_helper(e)) { + fprintf(stderr, "bind_fn return(1) first\n"); + return 0; + } + fprintf(stderr, "bind_fn return(1)\n"); + return 1; + } +IMPLEMENT_DYNAMIC_CHECK_FN() +IMPLEMENT_DYNAMIC_BIND_FN(bind_fn) +#endif /* ENGINE_DYNAMIC_SUPPORT */ + +#endif /* !NO_HW_CLUSTER_LABS */ +#endif /* !NO_HW */ + diff --git a/demos/engines/cluster_labs/hw_cluster_labs.ec b/demos/engines/cluster_labs/hw_cluster_labs.ec new file mode 100644 index 0000000..1f64786 --- /dev/null +++ b/demos/engines/cluster_labs/hw_cluster_labs.ec @@ -0,0 +1,8 @@ +# configuration file for util/mkerr.pl +# +# use like this: +# +# perl ../../../util/mkerr.pl -conf hw_cluster_labs.ec \ +# -nostatic -staticloader -write *.c + +L CL hw_cluster_labs_err.h hw_cluster_labs_err.c diff --git a/demos/engines/cluster_labs/hw_cluster_labs_err.c b/demos/engines/cluster_labs/hw_cluster_labs_err.c new file mode 100644 index 0000000..a7fa408 --- /dev/null +++ b/demos/engines/cluster_labs/hw_cluster_labs_err.c @@ -0,0 +1,151 @@ +/* hw_cluster_labs_err.c */ +/* ==================================================================== + * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include +#include +#include "hw_cluster_labs_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR +static ERR_STRING_DATA CL_str_functs[]= + { +{ERR_PACK(0,CL_F_CLUSTER_LABS_CTRL,0), "CLUSTER_LABS_CTRL"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_DSA_SIGN,0), "CLUSTER_LABS_DSA_SIGN"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_DSA_VERIFY,0), "CLUSTER_LABS_DSA_VERIFY"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_FINISH,0), "CLUSTER_LABS_FINISH"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_INIT,0), "CLUSTER_LABS_INIT"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_MOD_EXP,0), "CLUSTER_LABS_MOD_EXP"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_MOD_EXP_CRT,0), "CLUSTER_LABS_MOD_EXP_CRT"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_RAND_BYTES,0), "CLUSTER_LABS_RAND_BYTES"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_RSA_MOD_EXP,0), "CLUSTER_LABS_RSA_MOD_EXP"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_RSA_PRIV_DEC,0), "CLUSTER_LABS_RSA_PRIV_DEC"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_RSA_PRIV_ENC,0), "CLUSTER_LABS_RSA_PRIV_ENC"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_RSA_PUB_DEC,0), "CLUSTER_LABS_RSA_PUB_DEC"}, +{ERR_PACK(0,CL_F_CLUSTER_LABS_RSA_PUB_ENC,0), "CLUSTER_LABS_RSA_PUB_ENC"}, +{0,NULL} + }; + +static ERR_STRING_DATA CL_str_reasons[]= + { +{CL_R_ALREADY_LOADED ,"already loaded"}, +{CL_R_COMMAND_NOT_IMPLEMENTED ,"command not implemented"}, +{CL_R_DSO_FAILURE ,"dso failure"}, +{CL_R_FUNCTION_NOT_BINDED ,"function not binded"}, +{CL_R_INIT_FAILED ,"init failed"}, +{CL_R_NOT_LOADED ,"not loaded"}, +{0,NULL} + }; + +#endif + +#ifdef CL_LIB_NAME +static ERR_STRING_DATA CL_lib_name[]= + { +{0 ,CL_LIB_NAME}, +{0,NULL} + }; +#endif + + +static int CL_lib_error_code=0; +static int CL_error_init=1; + +static void ERR_load_CL_strings(void) + { + if (CL_lib_error_code == 0) + CL_lib_error_code=ERR_get_next_error_library(); + + if (CL_error_init) + { + CL_error_init=0; +#ifndef OPENSSL_NO_ERR + ERR_load_strings(CL_lib_error_code,CL_str_functs); + ERR_load_strings(CL_lib_error_code,CL_str_reasons); +#endif + +#ifdef CL_LIB_NAME + CL_lib_name->error = ERR_PACK(CL_lib_error_code,0,0); + ERR_load_strings(0,CL_lib_name); +#endif + } + } + +static void ERR_unload_CL_strings(void) + { + if (CL_error_init == 0) + { +#ifndef OPENSSL_NO_ERR + ERR_unload_strings(CL_lib_error_code,CL_str_functs); + ERR_unload_strings(CL_lib_error_code,CL_str_reasons); +#endif + +#ifdef CL_LIB_NAME + ERR_unload_strings(0,CL_lib_name); +#endif + CL_error_init=1; + } + } + +static void ERR_CL_error(int function, int reason, char *file, int line) + { + if (CL_lib_error_code == 0) + CL_lib_error_code=ERR_get_next_error_library(); + ERR_PUT_error(CL_lib_error_code,function,reason,file,line); + } diff --git a/demos/engines/cluster_labs/hw_cluster_labs_err.h b/demos/engines/cluster_labs/hw_cluster_labs_err.h new file mode 100644 index 0000000..f548a3b --- /dev/null +++ b/demos/engines/cluster_labs/hw_cluster_labs_err.h @@ -0,0 +1,99 @@ +/* ==================================================================== + * Copyright (c) 2001-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_CL_ERR_H +#define HEADER_CL_ERR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +static void ERR_load_CL_strings(void); +static void ERR_unload_CL_strings(void); +static void ERR_CL_error(int function, int reason, char *file, int line); +#define CLerr(f,r) ERR_CL_error((f),(r),__FILE__,__LINE__) + +/* Error codes for the CL functions. */ + +/* Function codes. */ +#define CL_F_CLUSTER_LABS_CTRL 100 +#define CL_F_CLUSTER_LABS_DSA_SIGN 101 +#define CL_F_CLUSTER_LABS_DSA_VERIFY 102 +#define CL_F_CLUSTER_LABS_FINISH 103 +#define CL_F_CLUSTER_LABS_INIT 104 +#define CL_F_CLUSTER_LABS_MOD_EXP 105 +#define CL_F_CLUSTER_LABS_MOD_EXP_CRT 106 +#define CL_F_CLUSTER_LABS_RAND_BYTES 107 +#define CL_F_CLUSTER_LABS_RSA_MOD_EXP 108 +#define CL_F_CLUSTER_LABS_RSA_PRIV_DEC 109 +#define CL_F_CLUSTER_LABS_RSA_PRIV_ENC 110 +#define CL_F_CLUSTER_LABS_RSA_PUB_DEC 111 +#define CL_F_CLUSTER_LABS_RSA_PUB_ENC 112 + +/* Reason codes. */ +#define CL_R_ALREADY_LOADED 100 +#define CL_R_COMMAND_NOT_IMPLEMENTED 101 +#define CL_R_DSO_FAILURE 102 +#define CL_R_FUNCTION_NOT_BINDED 103 +#define CL_R_INIT_FAILED 104 +#define CL_R_NOT_LOADED 105 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/demos/engines/ibmca/Makefile b/demos/engines/ibmca/Makefile new file mode 100644 index 0000000..72f3546 --- /dev/null +++ b/demos/engines/ibmca/Makefile @@ -0,0 +1,114 @@ +LIBNAME= libibmca +SRC= hw_ibmca.c +OBJ= hw_ibmca.o +HEADER= hw_ibmca.h + +CC= gcc +PIC= -fPIC +CFLAGS= -g -I../../../include $(PIC) -DENGINE_DYNAMIC_SUPPORT -DFLAT_INC +AR= ar r +RANLIB= ranlib + +LIB= $(LIBNAME).a +SHLIB= $(LIBNAME).so + +all: + @echo 'Please choose a system to build on:' + @echo '' + @echo 'tru64: Tru64 Unix, Digital Unix, Digital OSF/1' + @echo 'solaris: Solaris' + @echo 'irix: IRIX' + @echo 'hpux32: 32-bit HP/UX' + @echo 'hpux64: 64-bit HP/UX' + @echo 'aix: AIX' + @echo 'gnu: Generic GNU-based system (gcc and GNU ld)' + @echo '' + +FORCE.update: +update: FORCE.update + perl ../../../util/mkerr.pl -conf hw_ibmca.ec \ + -nostatic -staticloader -write hw_ibmca.c + +gnu: $(SHLIB).gnu +tru64: $(SHLIB).tru64 +solaris: $(SHLIB).solaris +irix: $(SHLIB).irix +hpux32: $(SHLIB).hpux32 +hpux64: $(SHLIB).hpux64 +aix: $(SHLIB).aix + +$(LIB): $(OBJ) + $(AR) $(LIB) $(OBJ) + - $(RANLIB) $(LIB) + +LINK_SO= \ + ld -r -o $(LIBNAME).o $$ALLSYMSFLAGS $(LIB) && \ + (nm -Pg $(LIBNAME).o | grep ' [BDT] ' | cut -f1 -d' ' > $(LIBNAME).exp; \ + $$SHAREDCMD $$SHAREDFLAGS -o $(SHLIB) $(LIBNAME).o -L ../../.. -lcrypto -lc) + +$(SHLIB).gnu: $(LIB) + ALLSYMSFLAGS='--whole-archive' \ + SHAREDFLAGS='-shared -Wl,-soname=$(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).gnu +$(SHLIB).tru64: $(LIB) + ALLSYMSFLAGS='-all' \ + SHAREDFLAGS='-shared' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).tru64 +$(SHLIB).solaris: $(LIB) + ALLSYMSFLAGS='-z allextract' \ + SHAREDFLAGS='-G -h $(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).solaris +$(SHLIB).irix: $(LIB) + ALLSYMSFLAGS='-all' \ + SHAREDFLAGS='-shared -Wl,-soname,$(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).irix +$(SHLIB).hpux32: $(LIB) + ALLSYMSFLAGS='-Fl' \ + SHAREDFLAGS='+vnocompatwarnings -b -z +s +h $(SHLIB)' \ + SHAREDCMD='/usr/ccs/bin/ld'; \ + $(LINK_SO) + touch $(SHLIB).hpux32 +$(SHLIB).hpux64: $(LIB) + ALLSYMSFLAGS='+forceload' \ + SHAREDFLAGS='-b -z +h $(SHLIB)' \ + SHAREDCMD='/usr/ccs/bin/ld'; \ + $(LINK_SO) + touch $(SHLIB).hpux64 +$(SHLIB).aix: $(LIB) + ALLSYMSFLAGS='-bnogc' \ + SHAREDFLAGS='-G -bE:$(LIBNAME).exp -bM:SRE' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).aix + +depend: + sed -e '/^# DO NOT DELETE.*/,$$d' < Makefile > Makefile.tmp + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' >> Makefile.tmp + gcc -M $(CFLAGS) $(SRC) >> Makefile.tmp + perl ../../../util/clean-depend.pl < Makefile.tmp > Makefile.new + rm -f Makefile.tmp Makefile + mv Makefile.new Makefile + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +rsaref.o: ../../../include/openssl/asn1.h ../../../include/openssl/bio.h +rsaref.o: ../../../include/openssl/bn.h ../../../include/openssl/crypto.h +rsaref.o: ../../../include/openssl/dh.h ../../../include/openssl/dsa.h +rsaref.o: ../../../include/openssl/e_os2.h ../../../include/openssl/engine.h +rsaref.o: ../../../include/openssl/err.h ../../../include/openssl/lhash.h +rsaref.o: ../../../include/openssl/opensslconf.h +rsaref.o: ../../../include/openssl/opensslv.h +rsaref.o: ../../../include/openssl/ossl_typ.h ../../../include/openssl/rand.h +rsaref.o: ../../../include/openssl/rsa.h ../../../include/openssl/safestack.h +rsaref.o: ../../../include/openssl/stack.h ../../../include/openssl/symhacks.h +rsaref.o: ../../../include/openssl/ui.h rsaref.c rsaref_err.c rsaref_err.h +rsaref.o: source/des.h source/global.h source/md2.h source/md5.h source/rsa.h +rsaref.o: source/rsaref.h diff --git a/demos/engines/ibmca/hw_ibmca.c b/demos/engines/ibmca/hw_ibmca.c new file mode 100644 index 0000000..0c2c39b --- /dev/null +++ b/demos/engines/ibmca/hw_ibmca.c @@ -0,0 +1,920 @@ +/* crypto/engine/hw_ibmca.c */ +/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* (C) COPYRIGHT International Business Machines Corp. 2001 */ + +#include +#include +#include +#include + +#ifndef OPENSSL_NO_HW +#ifndef OPENSSL_NO_HW_IBMCA + +#ifdef FLAT_INC +#include "ica_openssl_api.h" +#else +#include "vendor_defns/ica_openssl_api.h" +#endif + +#define IBMCA_LIB_NAME "ibmca engine" +#include "hw_ibmca_err.c" + +static int ibmca_destroy(ENGINE *e); +static int ibmca_init(ENGINE *e); +static int ibmca_finish(ENGINE *e); +static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()); + +static const char *IBMCA_F1 = "icaOpenAdapter"; +static const char *IBMCA_F2 = "icaCloseAdapter"; +static const char *IBMCA_F3 = "icaRsaModExpo"; +static const char *IBMCA_F4 = "icaRandomNumberGenerate"; +static const char *IBMCA_F5 = "icaRsaCrt"; + +ICA_ADAPTER_HANDLE handle=0; + +/* BIGNUM stuff */ +static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx); + +static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *q, const BIGNUM *dmp1, const BIGNUM *dmq1, + const BIGNUM *iqmp, BN_CTX *ctx); + +#ifndef OPENSSL_NO_RSA +/* RSA stuff */ +static int ibmca_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa); +#endif + +/* This function is aliased to mod_exp (with the mont stuff dropped). */ +static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); + +#ifndef OPENSSL_NO_DSA +/* DSA stuff */ +static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, + BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *in_mont); +static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); +#endif + +#ifndef OPENSSL_NO_DH +/* DH stuff */ +/* This function is alised to mod_exp (with the DH and mont dropped). */ +static int ibmca_mod_exp_dh(const DH *dh, BIGNUM *r, + const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +#endif + +/* RAND stuff */ +static int ibmca_rand_bytes(unsigned char *buf, int num); +static int ibmca_rand_status(void); + + +/* WJH - check for more commands, like in nuron */ + +/* The definitions for control commands specific to this engine */ +#define IBMCA_CMD_SO_PATH ENGINE_CMD_BASE +static const ENGINE_CMD_DEFN ibmca_cmd_defns[] = { + {IBMCA_CMD_SO_PATH, + "SO_PATH", + "Specifies the path to the 'atasi' shared library", + ENGINE_CMD_FLAG_STRING}, + {0, NULL, NULL, 0} + }; + +#ifndef OPENSSL_NO_RSA +/* Our internal RSA_METHOD that we provide pointers to */ +static RSA_METHOD ibmca_rsa = + { + "Ibmca RSA method", + NULL, + NULL, + NULL, + NULL, + ibmca_rsa_mod_exp, + ibmca_mod_exp_mont, + NULL, + NULL, + 0, + NULL, + NULL, + NULL + }; +#endif + +#ifndef OPENSSL_NO_DSA +/* Our internal DSA_METHOD that we provide pointers to */ +static DSA_METHOD ibmca_dsa = + { + "Ibmca DSA method", + NULL, /* dsa_do_sign */ + NULL, /* dsa_sign_setup */ + NULL, /* dsa_do_verify */ + ibmca_dsa_mod_exp, /* dsa_mod_exp */ + ibmca_mod_exp_dsa, /* bn_mod_exp */ + NULL, /* init */ + NULL, /* finish */ + 0, /* flags */ + NULL /* app_data */ + }; +#endif + +#ifndef OPENSSL_NO_DH +/* Our internal DH_METHOD that we provide pointers to */ +static DH_METHOD ibmca_dh = + { + "Ibmca DH method", + NULL, + NULL, + ibmca_mod_exp_dh, + NULL, + NULL, + 0, + NULL + }; +#endif + +static RAND_METHOD ibmca_rand = + { + /* "IBMCA RAND method", */ + NULL, + ibmca_rand_bytes, + NULL, + NULL, + ibmca_rand_bytes, + ibmca_rand_status, + }; + +/* Constants used when creating the ENGINE */ +static const char *engine_ibmca_id = "ibmca"; +static const char *engine_ibmca_name = "Ibmca hardware engine support"; + +/* This internal function is used by ENGINE_ibmca() and possibly by the + * "dynamic" ENGINE support too */ +static int bind_helper(ENGINE *e) + { +#ifndef OPENSSL_NO_RSA + const RSA_METHOD *meth1; +#endif +#ifndef OPENSSL_NO_DSA + const DSA_METHOD *meth2; +#endif +#ifndef OPENSSL_NO_DH + const DH_METHOD *meth3; +#endif + if(!ENGINE_set_id(e, engine_ibmca_id) || + !ENGINE_set_name(e, engine_ibmca_name) || +#ifndef OPENSSL_NO_RSA + !ENGINE_set_RSA(e, &ibmca_rsa) || +#endif +#ifndef OPENSSL_NO_DSA + !ENGINE_set_DSA(e, &ibmca_dsa) || +#endif +#ifndef OPENSSL_NO_DH + !ENGINE_set_DH(e, &ibmca_dh) || +#endif + !ENGINE_set_RAND(e, &ibmca_rand) || + !ENGINE_set_destroy_function(e, ibmca_destroy) || + !ENGINE_set_init_function(e, ibmca_init) || + !ENGINE_set_finish_function(e, ibmca_finish) || + !ENGINE_set_ctrl_function(e, ibmca_ctrl) || + !ENGINE_set_cmd_defns(e, ibmca_cmd_defns)) + return 0; + +#ifndef OPENSSL_NO_RSA + /* We know that the "PKCS1_SSLeay()" functions hook properly + * to the ibmca-specific mod_exp and mod_exp_crt so we use + * those functions. NB: We don't use ENGINE_openssl() or + * anything "more generic" because something like the RSAref + * code may not hook properly, and if you own one of these + * cards then you have the right to do RSA operations on it + * anyway! */ + meth1 = RSA_PKCS1_SSLeay(); + ibmca_rsa.rsa_pub_enc = meth1->rsa_pub_enc; + ibmca_rsa.rsa_pub_dec = meth1->rsa_pub_dec; + ibmca_rsa.rsa_priv_enc = meth1->rsa_priv_enc; + ibmca_rsa.rsa_priv_dec = meth1->rsa_priv_dec; +#endif + +#ifndef OPENSSL_NO_DSA + /* Use the DSA_OpenSSL() method and just hook the mod_exp-ish + * bits. */ + meth2 = DSA_OpenSSL(); + ibmca_dsa.dsa_do_sign = meth2->dsa_do_sign; + ibmca_dsa.dsa_sign_setup = meth2->dsa_sign_setup; + ibmca_dsa.dsa_do_verify = meth2->dsa_do_verify; +#endif + +#ifndef OPENSSL_NO_DH + /* Much the same for Diffie-Hellman */ + meth3 = DH_OpenSSL(); + ibmca_dh.generate_key = meth3->generate_key; + ibmca_dh.compute_key = meth3->compute_key; +#endif + + /* Ensure the ibmca error handling is set up */ + ERR_load_IBMCA_strings(); + return 1; + } + +static ENGINE *engine_ibmca(void) + { + ENGINE *ret = ENGINE_new(); + if(!ret) + return NULL; + if(!bind_helper(ret)) + { + ENGINE_free(ret); + return NULL; + } + return ret; + } + +#ifdef ENGINE_DYNAMIC_SUPPORT +static +#endif +void ENGINE_load_ibmca(void) + { + /* Copied from eng_[openssl|dyn].c */ + ENGINE *toadd = engine_ibmca(); + if(!toadd) return; + ENGINE_add(toadd); + ENGINE_free(toadd); + ERR_clear_error(); + } + +/* Destructor (complements the "ENGINE_ibmca()" constructor) */ +static int ibmca_destroy(ENGINE *e) + { + /* Unload the ibmca error strings so any error state including our + * functs or reasons won't lead to a segfault (they simply get displayed + * without corresponding string data because none will be found). */ + ERR_unload_IBMCA_strings(); + return 1; + } + + +/* This is a process-global DSO handle used for loading and unloading + * the Ibmca library. NB: This is only set (or unset) during an + * init() or finish() call (reference counts permitting) and they're + * operating with global locks, so this should be thread-safe + * implicitly. */ + +static DSO *ibmca_dso = NULL; + +/* These are the function pointers that are (un)set when the library has + * successfully (un)loaded. */ + +static unsigned int (ICA_CALL *p_icaOpenAdapter)(); +static unsigned int (ICA_CALL *p_icaCloseAdapter)(); +static unsigned int (ICA_CALL *p_icaRsaModExpo)(); +static unsigned int (ICA_CALL *p_icaRandomNumberGenerate)(); +static unsigned int (ICA_CALL *p_icaRsaCrt)(); + +/* utility function to obtain a context */ +static int get_context(ICA_ADAPTER_HANDLE *p_handle) + { + unsigned int status=0; + + status = p_icaOpenAdapter(0, p_handle); + if(status != 0) + return 0; + return 1; + } + +/* similarly to release one. */ +static void release_context(ICA_ADAPTER_HANDLE handle) + { + p_icaCloseAdapter(handle); + } + +/* (de)initialisation functions. */ +static int ibmca_init(ENGINE *e) + { + + void (*p1)(); + void (*p2)(); + void (*p3)(); + void (*p4)(); + void (*p5)(); + + if(ibmca_dso != NULL) + { + IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_ALREADY_LOADED); + goto err; + } + /* Attempt to load libatasi.so/atasi.dll/whatever. Needs to be + * changed unfortunately because the Ibmca drivers don't have + * standard library names that can be platform-translated well. */ + /* TODO: Work out how to actually map to the names the Ibmca + * drivers really use - for now a symbollic link needs to be + * created on the host system from libatasi.so to atasi.so on + * unix variants. */ + + /* WJH XXX check name translation */ + + ibmca_dso = DSO_load(NULL, IBMCA_LIBNAME, NULL, + /* DSO_FLAG_NAME_TRANSLATION */ 0); + if(ibmca_dso == NULL) + { + IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_DSO_FAILURE); + goto err; + } + + if(!(p1 = DSO_bind_func( + ibmca_dso, IBMCA_F1)) || + !(p2 = DSO_bind_func( + ibmca_dso, IBMCA_F2)) || + !(p3 = DSO_bind_func( + ibmca_dso, IBMCA_F3)) || + !(p4 = DSO_bind_func( + ibmca_dso, IBMCA_F4)) || + !(p5 = DSO_bind_func( + ibmca_dso, IBMCA_F5))) + { + IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_DSO_FAILURE); + goto err; + } + + /* Copy the pointers */ + + p_icaOpenAdapter = (unsigned int (ICA_CALL *)())p1; + p_icaCloseAdapter = (unsigned int (ICA_CALL *)())p2; + p_icaRsaModExpo = (unsigned int (ICA_CALL *)())p3; + p_icaRandomNumberGenerate = (unsigned int (ICA_CALL *)())p4; + p_icaRsaCrt = (unsigned int (ICA_CALL *)())p5; + + if(!get_context(&handle)) + { + IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_UNIT_FAILURE); + goto err; + } + + return 1; + err: + if(ibmca_dso) + DSO_free(ibmca_dso); + + p_icaOpenAdapter = NULL; + p_icaCloseAdapter = NULL; + p_icaRsaModExpo = NULL; + p_icaRandomNumberGenerate = NULL; + + return 0; + } + +static int ibmca_finish(ENGINE *e) + { + if(ibmca_dso == NULL) + { + IBMCAerr(IBMCA_F_IBMCA_FINISH,IBMCA_R_NOT_LOADED); + return 0; + } + release_context(handle); + if(!DSO_free(ibmca_dso)) + { + IBMCAerr(IBMCA_F_IBMCA_FINISH,IBMCA_R_DSO_FAILURE); + return 0; + } + ibmca_dso = NULL; + + return 1; + } + +static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()) + { + int initialised = ((ibmca_dso == NULL) ? 0 : 1); + switch(cmd) + { + case IBMCA_CMD_SO_PATH: + if(p == NULL) + { + IBMCAerr(IBMCA_F_IBMCA_CTRL,ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if(initialised) + { + IBMCAerr(IBMCA_F_IBMCA_CTRL,IBMCA_R_ALREADY_LOADED); + return 0; + } + IBMCA_LIBNAME = (const char *)p; + return 1; + default: + break; + } + IBMCAerr(IBMCA_F_IBMCA_CTRL,IBMCA_R_CTRL_COMMAND_NOT_IMPLEMENTED); + return 0; + } + + +static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx) + { + /* I need somewhere to store temporary serialised values for + * use with the Ibmca API calls. A neat cheat - I'll use + * BIGNUMs from the BN_CTX but access their arrays directly as + * byte arrays . This way I don't have to clean anything + * up. */ + + BIGNUM *argument=NULL; + BIGNUM *result=NULL; + BIGNUM *key=NULL; + int to_return; + int inLen, outLen, tmpLen; + + + ICA_KEY_RSA_MODEXPO *publKey=NULL; + unsigned int rc; + + to_return = 0; /* expect failure */ + + if(!ibmca_dso) + { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_NOT_LOADED); + goto err; + } + /* Prepare the params */ + BN_CTX_start(ctx); + argument = BN_CTX_get(ctx); + result = BN_CTX_get(ctx); + key = BN_CTX_get(ctx); + + if( !argument || !result || !key) + { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_CTX_FULL); + goto err; + } + + + if(!bn_wexpand(argument, m->top) || !bn_wexpand(result, m->top) || + !bn_wexpand(key, sizeof(*publKey)/BN_BYTES)) + + { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_EXPAND_FAIL); + goto err; + } + + publKey = (ICA_KEY_RSA_MODEXPO *)key->d; + + if (publKey == NULL) + { + goto err; + } + memset(publKey, 0, sizeof(ICA_KEY_RSA_MODEXPO)); + + publKey->keyType = CORRECT_ENDIANNESS(ME_KEY_TYPE); + publKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_MODEXPO)); + publKey->expOffset = (char *) publKey->keyRecord - (char *) publKey; + + /* A quirk of the card: the exponent length has to be the same + as the modulus (key) length */ + + outLen = BN_num_bytes(m); + +/* check for modulus length SAB*/ + if (outLen > 256 ) { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_MEXP_LENGTH_TO_LARGE); + goto err; + } +/* check for modulus length SAB*/ + + + publKey->expLength = publKey->nLength = outLen; +/* SAB Check for underflow condition + the size of the exponent is less than the size of the parameter + then we have a big problem and will underflow the keyRecord + buffer. Bad stuff could happen then +*/ +if (outLen < BN_num_bytes(p)){ + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_UNDERFLOW_KEYRECORD); + goto err; +} +/* SAB End check for underflow */ + + + BN_bn2bin(p, &publKey->keyRecord[publKey->expLength - + BN_num_bytes(p)]); + BN_bn2bin(m, &publKey->keyRecord[publKey->expLength]); + + + + publKey->modulusBitLength = CORRECT_ENDIANNESS(publKey->nLength * 8); + publKey->nOffset = CORRECT_ENDIANNESS(publKey->expOffset + + publKey->expLength); + + publKey->expOffset = CORRECT_ENDIANNESS((char *) publKey->keyRecord - + (char *) publKey); + + tmpLen = outLen; + publKey->expLength = publKey->nLength = CORRECT_ENDIANNESS(tmpLen); + + /* Prepare the argument */ + + memset(argument->d, 0, outLen); + BN_bn2bin(a, (unsigned char *)argument->d + outLen - + BN_num_bytes(a)); + + inLen = outLen; + + /* Perform the operation */ + + if( (rc = p_icaRsaModExpo(handle, inLen,(unsigned char *)argument->d, + publKey, &outLen, (unsigned char *)result->d)) + !=0 ) + + { + printf("rc = %d\n", rc); + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_REQUEST_FAILED); + goto err; + } + + + /* Convert the response */ + BN_bin2bn((unsigned char *)result->d, outLen, r); + to_return = 1; + err: + BN_CTX_end(ctx); + return to_return; + } + +#ifndef OPENSSL_NO_RSA +static int ibmca_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) + { + BN_CTX *ctx; + int to_return = 0; + + if((ctx = BN_CTX_new()) == NULL) + goto err; + if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) + { + if(!rsa->d || !rsa->n) + { + IBMCAerr(IBMCA_F_IBMCA_RSA_MOD_EXP, + IBMCA_R_MISSING_KEY_COMPONENTS); + goto err; + } + to_return = ibmca_mod_exp(r0, I, rsa->d, rsa->n, ctx); + } + else + { + to_return = ibmca_mod_exp_crt(r0, I, rsa->p, rsa->q, rsa->dmp1, + rsa->dmq1, rsa->iqmp, ctx); + } + err: + if(ctx) + BN_CTX_free(ctx); + return to_return; + } +#endif + +/* Ein kleines chinesisches "Restessen" */ +static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *q, const BIGNUM *dmp1, + const BIGNUM *dmq1, const BIGNUM *iqmp, BN_CTX *ctx) + { + + BIGNUM *argument = NULL; + BIGNUM *result = NULL; + BIGNUM *key = NULL; + + int to_return = 0; /* expect failure */ + + char *pkey=NULL; + ICA_KEY_RSA_CRT *privKey=NULL; + int inLen, outLen; + + int rc; + unsigned int offset, pSize, qSize; +/* SAB New variables */ + unsigned int keyRecordSize; + unsigned int pbytes = BN_num_bytes(p); + unsigned int qbytes = BN_num_bytes(q); + unsigned int dmp1bytes = BN_num_bytes(dmp1); + unsigned int dmq1bytes = BN_num_bytes(dmq1); + unsigned int iqmpbytes = BN_num_bytes(iqmp); + + /* Prepare the params */ + + BN_CTX_start(ctx); + argument = BN_CTX_get(ctx); + result = BN_CTX_get(ctx); + key = BN_CTX_get(ctx); + + if(!argument || !result || !key) + { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_CTX_FULL); + goto err; + } + + if(!bn_wexpand(argument, p->top + q->top) || + !bn_wexpand(result, p->top + q->top) || + !bn_wexpand(key, sizeof(*privKey)/BN_BYTES )) + { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_EXPAND_FAIL); + goto err; + } + + + privKey = (ICA_KEY_RSA_CRT *)key->d; +/* SAB Add check for total size in bytes of the parms does not exceed + the buffer space we have + do this first +*/ + keyRecordSize = pbytes+qbytes+dmp1bytes+dmq1bytes+iqmpbytes; + if ( keyRecordSize > sizeof(privKey->keyRecord )) { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); + goto err; + } + + if ( (qbytes + dmq1bytes) > 256 ){ + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); + goto err; + } + + if ( pbytes + dmp1bytes > 256 ) { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); + goto err; + } + +/* end SAB additions */ + + memset(privKey, 0, sizeof(ICA_KEY_RSA_CRT)); + privKey->keyType = CORRECT_ENDIANNESS(CRT_KEY_TYPE); + privKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_CRT)); + privKey->modulusBitLength = + CORRECT_ENDIANNESS(BN_num_bytes(q) * 2 * 8); + + /* + * p,dp & qInv are 1 QWORD Larger + */ + privKey->pLength = CORRECT_ENDIANNESS(BN_num_bytes(p)+8); + privKey->qLength = CORRECT_ENDIANNESS(BN_num_bytes(q)); + privKey->dpLength = CORRECT_ENDIANNESS(BN_num_bytes(dmp1)+8); + privKey->dqLength = CORRECT_ENDIANNESS(BN_num_bytes(dmq1)); + privKey->qInvLength = CORRECT_ENDIANNESS(BN_num_bytes(iqmp)+8); + + offset = (char *) privKey->keyRecord + - (char *) privKey; + + qSize = BN_num_bytes(q); + pSize = qSize + 8; /* 1 QWORD larger */ + + +/* SAB probably aittle redundant, but we'll verify that each of the + components which make up a key record sent ot the card does not exceed + the space that is allocated for it. this handles the case where even if + the total length does not exceed keyrecord zied, if the operands are funny sized +they could cause potential side affects on either the card or the result */ + + if ( (pbytes > pSize) || (dmp1bytes > pSize) || + (iqmpbytes > pSize) || ( qbytes >qSize) || + (dmq1bytes > qSize) ) { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE); + goto err; + + } + + + privKey->dpOffset = CORRECT_ENDIANNESS(offset); + + offset += pSize; + privKey->dqOffset = CORRECT_ENDIANNESS(offset); + + offset += qSize; + privKey->pOffset = CORRECT_ENDIANNESS(offset); + + offset += pSize; + privKey->qOffset = CORRECT_ENDIANNESS(offset); + + offset += qSize; + privKey->qInvOffset = CORRECT_ENDIANNESS(offset); + + pkey = (char *) privKey->keyRecord; + + +/* SAB first check that we don;t under flow the buffer */ + if ( pSize < pbytes ) { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_UNDERFLOW_CONDITION); + goto err; + } + + /* pkey += pSize - BN_num_bytes(p); WROING this should be dmp1) */ + pkey += pSize - BN_num_bytes(dmp1); + BN_bn2bin(dmp1, pkey); + pkey += BN_num_bytes(dmp1); /* move the pointer */ + + BN_bn2bin(dmq1, pkey); /* Copy over dmq1 */ + + pkey += qSize; /* move pointer */ + pkey += pSize - BN_num_bytes(p); /* set up for zero padding of next field */ + + BN_bn2bin(p, pkey); + pkey += BN_num_bytes(p); /* increment pointer by number of bytes moved */ + + BN_bn2bin(q, pkey); + pkey += qSize ; /* move the pointer */ + pkey += pSize - BN_num_bytes(iqmp); /* Adjust for padding */ + BN_bn2bin(iqmp, pkey); + + /* Prepare the argument and response */ + + outLen = CORRECT_ENDIANNESS(privKey->qLength) * 2; /* Correct endianess is used + because the fields were converted above */ + + if (outLen > 256) { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OUTLEN_TO_LARGE); + goto err; + } + + /* SAB check for underflow here on the argeument */ + if ( outLen < BN_num_bytes(a)) { + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_UNDERFLOW_CONDITION); + goto err; + } + + BN_bn2bin(a, (unsigned char *)argument->d + outLen - + BN_num_bytes(a)); + inLen = outLen; + + memset(result->d, 0, outLen); + + /* Perform the operation */ + + if ( (rc = p_icaRsaCrt(handle, inLen, (unsigned char *)argument->d, + privKey, &outLen, (unsigned char *)result->d)) != 0) + { + printf("rc = %d\n", rc); + IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_REQUEST_FAILED); + goto err; + } + + /* Convert the response */ + + BN_bin2bn((unsigned char *)result->d, outLen, r); + to_return = 1; + + err: + BN_CTX_end(ctx); + return to_return; + + } + +#ifndef OPENSSL_NO_DSA +/* This code was liberated and adapted from the commented-out code in + * dsa_ossl.c. Because of the unoptimised form of the Ibmca acceleration + * (it doesn't have a CRT form for RSA), this function means that an + * Ibmca system running with a DSA server certificate can handshake + * around 5 or 6 times faster/more than an equivalent system running with + * RSA. Just check out the "signs" statistics from the RSA and DSA parts + * of "openssl speed -engine ibmca dsa1024 rsa1024". */ +static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, + BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *in_mont) + { + BIGNUM t; + int to_return = 0; + + BN_init(&t); + /* let rr = a1 ^ p1 mod m */ + if (!ibmca_mod_exp(rr,a1,p1,m,ctx)) goto end; + /* let t = a2 ^ p2 mod m */ + if (!ibmca_mod_exp(&t,a2,p2,m,ctx)) goto end; + /* let rr = rr * t mod m */ + if (!BN_mod_mul(rr,rr,&t,m,ctx)) goto end; + to_return = 1; + end: + BN_free(&t); + return to_return; + } + + +static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx) + { + return ibmca_mod_exp(r, a, p, m, ctx); + } +#endif + +/* This function is aliased to mod_exp (with the mont stuff dropped). */ +static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) + { + return ibmca_mod_exp(r, a, p, m, ctx); + } + +#ifndef OPENSSL_NO_DH +/* This function is aliased to mod_exp (with the dh and mont dropped). */ +static int ibmca_mod_exp_dh(DH const *dh, BIGNUM *r, + const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) + { + return ibmca_mod_exp(r, a, p, m, ctx); + } +#endif + +/* Random bytes are good */ +static int ibmca_rand_bytes(unsigned char *buf, int num) + { + int to_return = 0; /* assume failure */ + unsigned int ret; + + + if(handle == 0) + { + IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_NOT_INITIALISED); + goto err; + } + + ret = p_icaRandomNumberGenerate(handle, num, buf); + if (ret < 0) + { + IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_REQUEST_FAILED); + goto err; + } + to_return = 1; + err: + return to_return; + } + +static int ibmca_rand_status(void) + { + return 1; + } + +/* This stuff is needed if this ENGINE is being compiled into a self-contained + * shared-library. */ +#ifdef ENGINE_DYNAMIC_SUPPORT +static int bind_fn(ENGINE *e, const char *id) + { + if(id && (strcmp(id, engine_ibmca_id) != 0)) /* WJH XXX */ + return 0; + if(!bind_helper(e)) + return 0; + return 1; + } +IMPLEMENT_DYNAMIC_CHECK_FN() +IMPLEMENT_DYNAMIC_BIND_FN(bind_fn) +#endif /* ENGINE_DYNAMIC_SUPPORT */ + + +#endif /* !OPENSSL_NO_HW_IBMCA */ +#endif /* !OPENSSL_NO_HW */ diff --git a/demos/engines/ibmca/hw_ibmca.ec b/demos/engines/ibmca/hw_ibmca.ec new file mode 100644 index 0000000..f68646d --- /dev/null +++ b/demos/engines/ibmca/hw_ibmca.ec @@ -0,0 +1,8 @@ +# configuration file for util/mkerr.pl +# +# use like this: +# +# perl ../../../util/mkerr.pl -conf hw_ibmca.ec \ +# -nostatic -staticloader -write *.c + +L IBMCA hw_ibmca_err.h hw_ibmca_err.c diff --git a/demos/engines/ibmca/hw_ibmca_err.c b/demos/engines/ibmca/hw_ibmca_err.c new file mode 100644 index 0000000..c4053f6 --- /dev/null +++ b/demos/engines/ibmca/hw_ibmca_err.c @@ -0,0 +1,154 @@ +/* hw_ibmca_err.c */ +/* ==================================================================== + * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include +#include +#include "hw_ibmca_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR +static ERR_STRING_DATA IBMCA_str_functs[]= + { +{ERR_PACK(0,IBMCA_F_IBMCA_CTRL,0), "IBMCA_CTRL"}, +{ERR_PACK(0,IBMCA_F_IBMCA_FINISH,0), "IBMCA_FINISH"}, +{ERR_PACK(0,IBMCA_F_IBMCA_INIT,0), "IBMCA_INIT"}, +{ERR_PACK(0,IBMCA_F_IBMCA_MOD_EXP,0), "IBMCA_MOD_EXP"}, +{ERR_PACK(0,IBMCA_F_IBMCA_MOD_EXP_CRT,0), "IBMCA_MOD_EXP_CRT"}, +{ERR_PACK(0,IBMCA_F_IBMCA_RAND_BYTES,0), "IBMCA_RAND_BYTES"}, +{ERR_PACK(0,IBMCA_F_IBMCA_RSA_MOD_EXP,0), "IBMCA_RSA_MOD_EXP"}, +{0,NULL} + }; + +static ERR_STRING_DATA IBMCA_str_reasons[]= + { +{IBMCA_R_ALREADY_LOADED ,"already loaded"}, +{IBMCA_R_BN_CTX_FULL ,"bn ctx full"}, +{IBMCA_R_BN_EXPAND_FAIL ,"bn expand fail"}, +{IBMCA_R_CTRL_COMMAND_NOT_IMPLEMENTED ,"ctrl command not implemented"}, +{IBMCA_R_DSO_FAILURE ,"dso failure"}, +{IBMCA_R_MEXP_LENGTH_TO_LARGE ,"mexp length to large"}, +{IBMCA_R_MISSING_KEY_COMPONENTS ,"missing key components"}, +{IBMCA_R_NOT_INITIALISED ,"not initialised"}, +{IBMCA_R_NOT_LOADED ,"not loaded"}, +{IBMCA_R_OPERANDS_TO_LARGE ,"operands to large"}, +{IBMCA_R_OUTLEN_TO_LARGE ,"outlen to large"}, +{IBMCA_R_REQUEST_FAILED ,"request failed"}, +{IBMCA_R_UNDERFLOW_CONDITION ,"underflow condition"}, +{IBMCA_R_UNDERFLOW_KEYRECORD ,"underflow keyrecord"}, +{IBMCA_R_UNIT_FAILURE ,"unit failure"}, +{0,NULL} + }; + +#endif + +#ifdef IBMCA_LIB_NAME +static ERR_STRING_DATA IBMCA_lib_name[]= + { +{0 ,IBMCA_LIB_NAME}, +{0,NULL} + }; +#endif + + +static int IBMCA_lib_error_code=0; +static int IBMCA_error_init=1; + +static void ERR_load_IBMCA_strings(void) + { + if (IBMCA_lib_error_code == 0) + IBMCA_lib_error_code=ERR_get_next_error_library(); + + if (IBMCA_error_init) + { + IBMCA_error_init=0; +#ifndef OPENSSL_NO_ERR + ERR_load_strings(IBMCA_lib_error_code,IBMCA_str_functs); + ERR_load_strings(IBMCA_lib_error_code,IBMCA_str_reasons); +#endif + +#ifdef IBMCA_LIB_NAME + IBMCA_lib_name->error = ERR_PACK(IBMCA_lib_error_code,0,0); + ERR_load_strings(0,IBMCA_lib_name); +#endif + } + } + +static void ERR_unload_IBMCA_strings(void) + { + if (IBMCA_error_init == 0) + { +#ifndef OPENSSL_NO_ERR + ERR_unload_strings(IBMCA_lib_error_code,IBMCA_str_functs); + ERR_unload_strings(IBMCA_lib_error_code,IBMCA_str_reasons); +#endif + +#ifdef IBMCA_LIB_NAME + ERR_unload_strings(0,IBMCA_lib_name); +#endif + IBMCA_error_init=1; + } + } + +static void ERR_IBMCA_error(int function, int reason, char *file, int line) + { + if (IBMCA_lib_error_code == 0) + IBMCA_lib_error_code=ERR_get_next_error_library(); + ERR_PUT_error(IBMCA_lib_error_code,function,reason,file,line); + } diff --git a/demos/engines/ibmca/hw_ibmca_err.h b/demos/engines/ibmca/hw_ibmca_err.h new file mode 100644 index 0000000..2070f95 --- /dev/null +++ b/demos/engines/ibmca/hw_ibmca_err.h @@ -0,0 +1,102 @@ +/* ==================================================================== + * Copyright (c) 2001-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_IBMCA_ERR_H +#define HEADER_IBMCA_ERR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +static void ERR_load_IBMCA_strings(void); +static void ERR_unload_IBMCA_strings(void); +static void ERR_IBMCA_error(int function, int reason, char *file, int line); +#define IBMCAerr(f,r) ERR_IBMCA_error((f),(r),__FILE__,__LINE__) + +/* Error codes for the IBMCA functions. */ + +/* Function codes. */ +#define IBMCA_F_IBMCA_CTRL 100 +#define IBMCA_F_IBMCA_FINISH 101 +#define IBMCA_F_IBMCA_INIT 102 +#define IBMCA_F_IBMCA_MOD_EXP 103 +#define IBMCA_F_IBMCA_MOD_EXP_CRT 104 +#define IBMCA_F_IBMCA_RAND_BYTES 105 +#define IBMCA_F_IBMCA_RSA_MOD_EXP 106 + +/* Reason codes. */ +#define IBMCA_R_ALREADY_LOADED 100 +#define IBMCA_R_BN_CTX_FULL 101 +#define IBMCA_R_BN_EXPAND_FAIL 102 +#define IBMCA_R_CTRL_COMMAND_NOT_IMPLEMENTED 103 +#define IBMCA_R_DSO_FAILURE 104 +#define IBMCA_R_MEXP_LENGTH_TO_LARGE 105 +#define IBMCA_R_MISSING_KEY_COMPONENTS 106 +#define IBMCA_R_NOT_INITIALISED 107 +#define IBMCA_R_NOT_LOADED 108 +#define IBMCA_R_OPERANDS_TO_LARGE 109 +#define IBMCA_R_OUTLEN_TO_LARGE 110 +#define IBMCA_R_REQUEST_FAILED 111 +#define IBMCA_R_UNDERFLOW_CONDITION 112 +#define IBMCA_R_UNDERFLOW_KEYRECORD 113 +#define IBMCA_R_UNIT_FAILURE 114 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/demos/engines/ibmca/ica_openssl_api.h b/demos/engines/ibmca/ica_openssl_api.h new file mode 100644 index 0000000..c77e0fd --- /dev/null +++ b/demos/engines/ibmca/ica_openssl_api.h @@ -0,0 +1,189 @@ + +#ifndef __ICA_OPENSSL_API_H__ +#define __ICA_OPENSSL_API_H__ + +/** + ** abstract data types for API + **/ + +#define ICA_ADAPTER_HANDLE int + +#if defined(linux) || defined (_AIX) +#define ICA_CALL +#endif + +#if defined(WIN32) || defined(_WIN32) +#define ICA_CALL __stdcall +#endif + +/*------------------------------------------------* + | RSA defines and typedefs | + *------------------------------------------------*/ + /* + * All data elements of the RSA key are in big-endian format + * Modulus-Exponent form of key + * + */ + #define MAX_EXP_SIZE 256 + #define MAX_MODULUS_SIZE 256 + #define MAX_MODEXP_SIZE (MAX_EXP_SIZE + MAX_MODULUS_SIZE) + + #define MAX_OPERAND_SIZE MAX_EXP_SIZE + + typedef unsigned char ICA_KEY_RSA_MODEXPO_REC[MAX_MODEXP_SIZE]; + /* + * All data elements of the RSA key are in big-endian format + * Chinese Remainder Thereom(CRT) form of key + * Used only for Decrypt, the encrypt form is typically Modulus-Exponent + * + */ + #define MAX_BP_SIZE 136 + #define MAX_BQ_SIZE 128 + #define MAX_NP_SIZE 136 + #define MAX_NQ_SIZE 128 + #define MAX_QINV_SIZE 136 + #define MAX_RSACRT_SIZE (MAX_BP_SIZE+MAX_BQ_SIZE+MAX_NP_SIZE+MAX_NQ_SIZE+MAX_QINV_SIZE) + +#define RSA_GEN_OPERAND_MAX 256 /* bytes */ + +typedef unsigned char ICA_KEY_RSA_CRT_REC[MAX_RSACRT_SIZE]; +/*------------------------------------------------* + | RSA key token types | + *------------------------------------------------*/ + +#define RSA_PUBLIC_MODULUS_EXPONENT 3 +#define RSA_PKCS_PRIVATE_CHINESE_REMAINDER 6 + +#define KEYTYPE_MODEXPO 1 +#define KEYTYPE_PKCSCRT 2 + + +/*------------------------------------------------* + | RSA Key Token format | + *------------------------------------------------*/ + +/* + * NOTE: All the fields in the ICA_KEY_RSA_MODEXPO structure + * (lengths, offsets, exponents, modulus, etc.) are + * stored in big-endian format + */ + +typedef struct _ICA_KEY_RSA_MODEXPO +{ unsigned int keyType; /* RSA key type. */ + unsigned int keyLength; /* Total length of the token. */ + unsigned int modulusBitLength; /* Modulus n bit length. */ + /* -- Start of the data length.*/ + unsigned int nLength; /* Modulus n = p * q */ + unsigned int expLength; /* exponent (public or private)*/ + /* e = 1/d * mod(p-1)(q-1) */ + /* -- Start of the data offsets*/ + unsigned int nOffset; /* Modulus n . */ + unsigned int expOffset; /* exponent (public or private)*/ + unsigned char reserved[112]; /* reserved area */ + /* -- Start of the variable -- */ + /* -- length token data. -- */ + ICA_KEY_RSA_MODEXPO_REC keyRecord; +} ICA_KEY_RSA_MODEXPO; +#define SZ_HEADER_MODEXPO (sizeof(ICA_KEY_RSA_MODEXPO) - sizeof(ICA_KEY_RSA_MODEXPO_REC)) + +/* + * NOTE: All the fields in the ICA_KEY_RSA_CRT structure + * (lengths, offsets, exponents, modulus, etc.) are + * stored in big-endian format + */ + +typedef struct _ICA_KEY_RSA_CRT +{ unsigned int keyType; /* RSA key type. */ + unsigned int keyLength; /* Total length of the token. */ + unsigned int modulusBitLength; /* Modulus n bit length. */ + /* -- Start of the data length.*/ +#if _AIX + unsigned int nLength; /* Modulus n = p * q */ +#endif + unsigned int pLength; /* Prime number p . */ + unsigned int qLength; /* Prime number q . */ + unsigned int dpLength; /* dp = d * mod(p-1) . */ + unsigned int dqLength; /* dq = d * mod(q-1) . */ + unsigned int qInvLength; /* PKCS: qInv = Ap/q */ + /* -- Start of the data offsets*/ +#if _AIX + unsigned int nOffset; /* Modulus n . */ +#endif + unsigned int pOffset; /* Prime number p . */ + unsigned int qOffset; /* Prime number q . */ + unsigned int dpOffset; /* dp . */ + unsigned int dqOffset; /* dq . */ + unsigned int qInvOffset; /* qInv for PKCS */ +#if _AIX + unsigned char reserved[80]; /* reserved area */ +#else + unsigned char reserved[88]; /* reserved area */ +#endif + /* -- Start of the variable -- */ + /* -- length token data. -- */ + ICA_KEY_RSA_CRT_REC keyRecord; +} ICA_KEY_RSA_CRT; +#define SZ_HEADER_CRT (sizeof(ICA_KEY_RSA_CRT) - sizeof(ICA_KEY_RSA_CRT_REC)) + +unsigned int +icaOpenAdapter( unsigned int adapterId, + ICA_ADAPTER_HANDLE *pAdapterHandle ); + +unsigned int +icaCloseAdapter( ICA_ADAPTER_HANDLE adapterHandle ); + +unsigned int +icaRsaModExpo( ICA_ADAPTER_HANDLE hAdapterHandle, + unsigned int inputDataLength, + unsigned char *pInputData, + ICA_KEY_RSA_MODEXPO *pKeyModExpo, + unsigned int *pOutputDataLength, + unsigned char *pOutputData ); + +unsigned int +icaRsaCrt( ICA_ADAPTER_HANDLE hAdapterHandle, + unsigned int inputDataLength, + unsigned char *pInputData, + ICA_KEY_RSA_CRT *pKeyCrt, + unsigned int *pOutputDataLength, + unsigned char *pOutputData ); + +unsigned int +icaRandomNumberGenerate( ICA_ADAPTER_HANDLE hAdapterHandle, + unsigned int outputDataLength, + unsigned char *pOutputData ); + +/* Specific macros and definitions to not have IFDEF;s all over the + main code */ + +#if (_AIX) +static const char *IBMCA_LIBNAME = "/lib/libica.a(shr.o)"; +#elif (WIN32) +static const char *IBMCA_LIBNAME = "cryptica"; +#else +static const char *IBMCA_LIBNAME = "ica"; +#endif + +#if (WIN32) +/* + The ICA_KEY_RSA_MODEXPO & ICA_KEY_RSA_CRT lengths and + offsets must be in big-endian format. + +*/ +#define CORRECT_ENDIANNESS(b) ( \ + (((unsigned long) (b) & 0x000000ff) << 24) | \ + (((unsigned long) (b) & 0x0000ff00) << 8) | \ + (((unsigned long) (b) & 0x00ff0000) >> 8) | \ + (((unsigned long) (b) & 0xff000000) >> 24) \ + ) +#define CRT_KEY_TYPE RSA_PKCS_PRIVATE_CHINESE_REMAINDER +#define ME_KEY_TYPE RSA_PUBLIC_MODULUS_EXPONENT +#else +#define CORRECT_ENDIANNESS(b) (b) +#define CRT_KEY_TYPE KEYTYPE_PKCSCRT +#define ME_KEY_TYPE KEYTYPE_MODEXPO +#endif + + + +#endif /* __ICA_OPENSSL_API_H__ */ diff --git a/demos/engines/rsaref/Makefile b/demos/engines/rsaref/Makefile new file mode 100644 index 0000000..63b8c79 --- /dev/null +++ b/demos/engines/rsaref/Makefile @@ -0,0 +1,135 @@ +LIBNAME= librsaref +SRC= rsaref.c +OBJ= rsaref.o +HEADER= rsaref.h + +CC= gcc +PIC= -fPIC +CFLAGS= -g -I../../../include $(PIC) -DENGINE_DYNAMIC_SUPPORT +AR= ar r +RANLIB= ranlib + +LIB= $(LIBNAME).a +SHLIB= $(LIBNAME).so + +all: + @echo 'Please choose a system to build on:' + @echo '' + @echo 'tru64: Tru64 Unix, Digital Unix, Digital OSF/1' + @echo 'solaris: Solaris' + @echo 'irix: IRIX' + @echo 'hpux32: 32-bit HP/UX' + @echo 'hpux64: 64-bit HP/UX' + @echo 'aix: AIX' + @echo 'gnu: Generic GNU-based system (gcc and GNU ld)' + @echo '' + +FORCE.install: +install: FORCE.install + cd install; \ + make -f unix/makefile CFLAGS='-I. -DPROTOTYPES=1 -O -c' RSAREFLIB=librsaref.a librsaref.a + +FORCE.update: +update: FORCE.update + perl ../../../util/mkerr.pl -conf rsaref.ec \ + -nostatic -staticloader -write rsaref.c + +darwin: install $(SHLIB).darwin +cygwin: install $(SHLIB).cygwin +gnu: install $(SHLIB).gnu +alpha-osf1: install $(SHLIB).alpha-osf1 +tru64: install $(SHLIB).tru64 +solaris: install $(SHLIB).solaris +irix: install $(SHLIB).irix +hpux32: install $(SHLIB).hpux32 +hpux64: install $(SHLIB).hpux64 +aix: install $(SHLIB).aix +reliantunix: install $(SHLIB).reliantunix + +$(LIB): $(OBJ) + $(AR) $(LIB) $(OBJ) + - $(RANLIB) $(LIB) + +LINK_SO= \ + ld -r -o $(LIBNAME).o $$ALLSYMSFLAGS $(LIB) install/librsaref.a && \ + (nm -Pg $(LIBNAME).o | grep ' [BDT] ' | cut -f1 -d' ' > $(LIBNAME).exp; \ + $$SHAREDCMD $$SHAREDFLAGS -o $(SHLIB) $(LIBNAME).o -L ../../.. -lcrypto -lc) + +$(SHLIB).darwin: $(LIB) install/librsaref.a + ALLSYMSFLAGS='-all_load' \ + SHAREDFLAGS='-dynamiclib -install_name $(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).darwin +$(SHLIB).cygwin: $(LIB) install/librsaref.a + ALLSYMSFLAGS='--whole-archive' \ + SHAREDFLAGS='-shared -Wl,-Bsymbolic -Wl,--out-implib,$(LIBNAME).dll.a' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).cygwin +$(SHLIB).gnu: $(LIB) install/librsaref.a + ALLSYMSFLAGS='--whole-archive' \ + SHAREDFLAGS='-shared -Wl,-soname=$(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).gnu +$(SHLIB).tru64: $(LIB) install/librsaref.a + ALLSYMSFLAGS='-all' \ + SHAREDFLAGS='-shared' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).tru64 +$(SHLIB).solaris: $(LIB) install/librsaref.a + ALLSYMSFLAGS='-z allextract' \ + SHAREDFLAGS='-G -h $(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).solaris +$(SHLIB).irix: $(LIB) install/librsaref.a + ALLSYMSFLAGS='-all' \ + SHAREDFLAGS='-shared -Wl,-soname,$(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).irix +$(SHLIB).hpux32: $(LIB) install/librsaref.a + ALLSYMSFLAGS='-Fl' \ + SHAREDFLAGS='+vnocompatwarnings -b -z +s +h $(SHLIB)' \ + SHAREDCMD='/usr/ccs/bin/ld'; \ + $(LINK_SO) + touch $(SHLIB).hpux32 +$(SHLIB).hpux64: $(LIB) install/librsaref.a + ALLSYMSFLAGS='+forceload' \ + SHAREDFLAGS='-b -z +h $(SHLIB)' \ + SHAREDCMD='/usr/ccs/bin/ld'; \ + $(LINK_SO) + touch $(SHLIB).hpux64 +$(SHLIB).aix: $(LIB) install/librsaref.a + ALLSYMSFLAGS='-bnogc' \ + SHAREDFLAGS='-G -bE:$(LIBNAME).exp -bM:SRE' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).aix + +depend: + sed -e '/^# DO NOT DELETE.*/,$$d' < Makefile > Makefile.tmp + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' >> Makefile.tmp + gcc -M $(CFLAGS) $(SRC) >> Makefile.tmp + perl ../../../util/clean-depend.pl < Makefile.tmp > Makefile.new + rm -f Makefile.tmp Makefile + mv Makefile.new Makefile + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +rsaref.o: ../../../include/openssl/asn1.h ../../../include/openssl/bio.h +rsaref.o: ../../../include/openssl/bn.h ../../../include/openssl/crypto.h +rsaref.o: ../../../include/openssl/dh.h ../../../include/openssl/dsa.h +rsaref.o: ../../../include/openssl/e_os2.h ../../../include/openssl/engine.h +rsaref.o: ../../../include/openssl/err.h ../../../include/openssl/lhash.h +rsaref.o: ../../../include/openssl/opensslconf.h +rsaref.o: ../../../include/openssl/opensslv.h +rsaref.o: ../../../include/openssl/ossl_typ.h ../../../include/openssl/rand.h +rsaref.o: ../../../include/openssl/rsa.h ../../../include/openssl/safestack.h +rsaref.o: ../../../include/openssl/stack.h ../../../include/openssl/symhacks.h +rsaref.o: ../../../include/openssl/ui.h rsaref.c rsaref_err.c rsaref_err.h +rsaref.o: source/des.h source/global.h source/md2.h source/md5.h source/rsa.h +rsaref.o: source/rsaref.h diff --git a/demos/engines/rsaref/README b/demos/engines/rsaref/README new file mode 100644 index 0000000..00b1f74 --- /dev/null +++ b/demos/engines/rsaref/README @@ -0,0 +1,22 @@ +librsaref.so is a demonstration dynamic engine that does RSA +operations using the old RSAref 2.0 implementation. + +To make proper use of this engine, you must download RSAref 2.0 +(search the web for rsaref.tar.Z for example) and unpack it in this +directory, so you'll end up having the subdirectories "install" and +"source" among others. + +To build, do the following: + + make + +This will list a number of available targets to choose from. Most of +them are architecture-specific. The exception is "gnu" which is to be +used on systems where GNU ld and gcc have been installed in such a way +that gcc uses GNU ld to link together programs and shared libraries. + +The make file assumes you use gcc. To change that, just reassign CC: + + make CC=cc + +The result is librsaref.so, which you can copy to any place you wish. diff --git a/demos/engines/rsaref/build.com b/demos/engines/rsaref/build.com new file mode 100644 index 0000000..72b013d --- /dev/null +++ b/demos/engines/rsaref/build.com @@ -0,0 +1,105 @@ +$! BUILD.COM -- Building procedure for the RSAref engine +$ +$ if f$search("source.dir") .eqs. "" - + .or. f$search("install.dir") .eqs. "" +$ then +$ write sys$error "RSAref 2.0 hasn't been properly extracted." +$ exit +$ endif +$ +$ if (f$getsyi("cpu").lt.128) +$ then +$ arch := vax +$ else +$ arch = f$edit( f$getsyi( "ARCH_NAME"), "UPCASE") +$ if (arch .eqs. "") then arch = "UNK" +$ endif +$ +$ _save_default = f$environment("default") +$ set default [.install] +$ files := desc,digit,md2c,md5c,nn,prime,- + rsa,r_encode,r_dh,r_enhanc,r_keygen,r_random,- + r_stdlib +$ delete rsaref.olb;* +$ library/create/object rsaref.olb +$ files_i = 0 +$ rsaref_loop: +$ files_e = f$edit(f$element(files_i,",",files),"trim") +$ files_i = files_i + 1 +$ if files_e .eqs. "," then goto rsaref_loop_end +$ cc/include=([-.source],[])/define=PROTOTYPES=1/object=[]'files_e'.obj - + [-.source]'files_e'.c +$ library/replace/object rsaref.olb 'files_e'.obj +$ goto rsaref_loop +$ rsaref_loop_end: +$ +$ set default [-] +$ define/user openssl [---.include.openssl] +$ cc/define=ENGINE_DYNAMIC_SUPPORT rsaref.c +$ +$ if arch .eqs. "VAX" +$ then +$ macro/object=rsaref_vec.obj sys$input: +; +; Transfer vector for VAX shareable image +; + .TITLE librsaref +; +; Define macro to assist in building transfer vector entries. Each entry +; should take no more than 8 bytes. +; + .MACRO FTRANSFER_ENTRY routine + .ALIGN QUAD + .TRANSFER routine + .MASK routine + JMP routine+2 + .ENDM FTRANSFER_ENTRY +; +; Place entries in own program section. +; + .PSECT $$LIBRSAREF,QUAD,PIC,USR,CON,REL,LCL,SHR,EXE,RD,NOWRT + +LIBRSAREF_xfer: + FTRANSFER_ENTRY bind_engine + FTRANSFER_ENTRY v_check + +; +; Allocate extra storage at end of vector to allow for expansion. +; + .BLKB 512-<.-LIBRSAREF_xfer> ; 1 page. + .END +$ link/share=librsaref.exe sys$input:/option +! +! Ensure transfer vector is at beginning of image +! +CLUSTER=FIRST +COLLECT=FIRST,$$LIBRSAREF +! +! make psects nonshareable so image can be installed. +! +PSECT_ATTR=$CHAR_STRING_CONSTANTS,NOWRT +[]rsaref_vec.obj +[]rsaref.obj +[.install]rsaref.olb/lib +[---.vax.exe.crypto]libcrypto.olb/lib +$ else +$ if arch_name .eqs. "ALPHA" +$ then +$ link/share=librsaref.exe sys$input:/option +[]rsaref.obj +[.install]rsaref.olb/lib +[---.alpha.exe.crypto]libcrypto.olb/lib +symbol_vector=(bind_engine=procedure,v_check=procedure) +$ else +$ if arch_name .eqs. "IA64" +$ then +$ link /shareable=librsaref.exe sys$input: /options +[]rsaref.obj +[.install]rsaref.olb/lib +[---.ia64.exe.crypto]libcrypto.olb/lib +symbol_vector=(bind_engine=procedure,v_check=procedure) +$ endif +$ endif +$ endif +$ +$ set default '_save_default' diff --git a/demos/engines/rsaref/rsaref.c b/demos/engines/rsaref/rsaref.c new file mode 100644 index 0000000..f97974f --- /dev/null +++ b/demos/engines/rsaref/rsaref.c @@ -0,0 +1,685 @@ +/* Demo of how to construct your own engine and using it. The basis of this + engine is RSAref, an old reference of the RSA algorithm which can still + be found a little here and there. */ + +#include +#include +#include "./source/global.h" +#include "./source/rsaref.h" +#include "./source/rsa.h" +#include "./source/des.h" +#include +#define OPENSSL_NO_MD2 +#define OPENSSL_NO_MD5 +#include +#include +#include + +#define RSAREF_LIB_NAME "rsaref engine" +#include "rsaref_err.c" + +/***************************************************************************** + *** Function declarations and global variable definitions *** + *****************************************************************************/ + +/***************************************************************************** + * Constants used when creating the ENGINE + **/ +static const char *engine_rsaref_id = "rsaref"; +static const char *engine_rsaref_name = "RSAref engine support"; + +/***************************************************************************** + * Functions to handle the engine + **/ +static int rsaref_destroy(ENGINE *e); +static int rsaref_init(ENGINE *e); +static int rsaref_finish(ENGINE *e); +#if 0 +static int rsaref_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()); +#endif + +/***************************************************************************** + * Engine commands + **/ +static const ENGINE_CMD_DEFN rsaref_cmd_defns[] = { + {0, NULL, NULL, 0} + }; + +/***************************************************************************** + * RSA functions + **/ +static int rsaref_private_decrypt(int len, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +static int rsaref_private_encrypt(int len, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +static int rsaref_public_encrypt(int len, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +static int rsaref_public_decrypt(int len, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +static int bnref_mod_exp(BIGNUM *r,const BIGNUM *a,const BIGNUM *p,const BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *m_ctx); +static int rsaref_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa); + +/***************************************************************************** + * Our RSA method + **/ +static RSA_METHOD rsaref_rsa = +{ + "RSAref PKCS#1 RSA", + rsaref_public_encrypt, + rsaref_public_decrypt, + rsaref_private_encrypt, + rsaref_private_decrypt, + rsaref_mod_exp, + bnref_mod_exp, + NULL, + NULL, + 0, + NULL, + NULL, + NULL +}; + +/***************************************************************************** + * Symetric cipher and digest function registrars + **/ +static int rsaref_ciphers(ENGINE *e, const EVP_CIPHER **cipher, + const int **nids, int nid); +static int rsaref_digests(ENGINE *e, const EVP_MD **digest, + const int **nids, int nid); + +static int rsaref_cipher_nids[] = + { NID_des_cbc, NID_des_ede3_cbc, NID_desx_cbc, 0 }; +static int rsaref_digest_nids[] = + { NID_md2, NID_md5, 0 }; + +/***************************************************************************** + * DES functions + **/ +static int cipher_des_cbc_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); +static int cipher_des_cbc_code(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl); +static int cipher_des_cbc_clean(EVP_CIPHER_CTX *); +static int cipher_des_ede3_cbc_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); +static int cipher_des_ede3_cbc_code(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl); +static int cipher_des_ede3_cbc_clean(EVP_CIPHER_CTX *); +static int cipher_desx_cbc_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); +static int cipher_desx_cbc_code(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl); +static int cipher_desx_cbc_clean(EVP_CIPHER_CTX *); + +/***************************************************************************** + * Our DES ciphers + **/ +static const EVP_CIPHER cipher_des_cbc = + { + NID_des_cbc, + 8, 8, 8, + 0 | EVP_CIPH_CBC_MODE, + cipher_des_cbc_init, + cipher_des_cbc_code, + cipher_des_cbc_clean, + sizeof(DES_CBC_CTX), + NULL, + NULL, + NULL, + NULL + }; + +static const EVP_CIPHER cipher_des_ede3_cbc = + { + NID_des_ede3_cbc, + 8, 24, 8, + 0 | EVP_CIPH_CBC_MODE, + cipher_des_ede3_cbc_init, + cipher_des_ede3_cbc_code, + cipher_des_ede3_cbc_clean, + sizeof(DES3_CBC_CTX), + NULL, + NULL, + NULL, + NULL + }; + +static const EVP_CIPHER cipher_desx_cbc = + { + NID_desx_cbc, + 8, 24, 8, + 0 | EVP_CIPH_CBC_MODE, + cipher_desx_cbc_init, + cipher_desx_cbc_code, + cipher_desx_cbc_clean, + sizeof(DESX_CBC_CTX), + NULL, + NULL, + NULL, + NULL + }; + +/***************************************************************************** + * MD functions + **/ +static int digest_md2_init(EVP_MD_CTX *ctx); +static int digest_md2_update(EVP_MD_CTX *ctx,const void *data, + unsigned long count); +static int digest_md2_final(EVP_MD_CTX *ctx,unsigned char *md); +static int digest_md5_init(EVP_MD_CTX *ctx); +static int digest_md5_update(EVP_MD_CTX *ctx,const void *data, + unsigned long count); +static int digest_md5_final(EVP_MD_CTX *ctx,unsigned char *md); + +/***************************************************************************** + * Our MD digests + **/ +static const EVP_MD digest_md2 = + { + NID_md2, + NID_md2WithRSAEncryption, + 16, + 0, + digest_md2_init, + digest_md2_update, + digest_md2_final, + NULL, + NULL, + EVP_PKEY_RSA_method, + 16, + sizeof(MD2_CTX) + }; + +static const EVP_MD digest_md5 = + { + NID_md5, + NID_md5WithRSAEncryption, + 16, + 0, + digest_md5_init, + digest_md5_update, + digest_md5_final, + NULL, + NULL, + EVP_PKEY_RSA_method, + 64, + sizeof(MD5_CTX) + }; + +/***************************************************************************** + *** Function definitions *** + *****************************************************************************/ + +/***************************************************************************** + * Functions to handle the engine + **/ + +static int bind_rsaref(ENGINE *e) + { + const RSA_METHOD *meth1; + if(!ENGINE_set_id(e, engine_rsaref_id) + || !ENGINE_set_name(e, engine_rsaref_name) + || !ENGINE_set_RSA(e, &rsaref_rsa) + || !ENGINE_set_ciphers(e, rsaref_ciphers) + || !ENGINE_set_digests(e, rsaref_digests) + || !ENGINE_set_destroy_function(e, rsaref_destroy) + || !ENGINE_set_init_function(e, rsaref_init) + || !ENGINE_set_finish_function(e, rsaref_finish) + /* || !ENGINE_set_ctrl_function(e, rsaref_ctrl) */ + /* || !ENGINE_set_cmd_defns(e, rsaref_cmd_defns) */) + return 0; + + /* Ensure the rsaref error handling is set up */ + ERR_load_RSAREF_strings(); + return 1; + } + +#ifdef ENGINE_DYNAMIC_SUPPORT +static int bind_helper(ENGINE *e, const char *id) + { + if(id && (strcmp(id, engine_rsaref_id) != 0)) + return 0; + if(!bind_rsaref(e)) + return 0; + return 1; + } +IMPLEMENT_DYNAMIC_CHECK_FN() +IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) +#else +static ENGINE *engine_rsaref(void) + { + ENGINE *ret = ENGINE_new(); + if(!ret) + return NULL; + if(!bind_rsaref(ret)) + { + ENGINE_free(ret); + return NULL; + } + return ret; + } + +void ENGINE_load_rsaref(void) + { + /* Copied from eng_[openssl|dyn].c */ + ENGINE *toadd = engine_rsaref(); + if(!toadd) return; + ENGINE_add(toadd); + ENGINE_free(toadd); + ERR_clear_error(); + } +#endif + +/* Initiator which is only present to make sure this engine looks available */ +static int rsaref_init(ENGINE *e) + { + return 1; + } + +/* Finisher which is only present to make sure this engine looks available */ +static int rsaref_finish(ENGINE *e) + { + return 1; + } + +/* Destructor (complements the "ENGINE_ncipher()" constructor) */ +static int rsaref_destroy(ENGINE *e) + { + ERR_unload_RSAREF_strings(); + return 1; + } + +/***************************************************************************** + * RSA functions + **/ + +static int rsaref_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) + { + RSAREFerr(RSAREF_F_RSAREF_MOD_EXP,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return(0); + } + +static int bnref_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) + { + RSAREFerr(RSAREF_F_BNREF_MOD_EXP,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return(0); + } + +/* unsigned char *to: [max] */ +static int RSAref_bn2bin(BIGNUM *from, unsigned char *to, int max) + { + int i; + + i=BN_num_bytes(from); + if (i > max) + { + RSAREFerr(RSAREF_F_RSAREF_BN2BIN,RSAREF_R_LEN); + return(0); + } + + memset(to,0,(unsigned int)max); + if (!BN_bn2bin(from,&(to[max-i]))) + return(0); + return(1); + } + +#ifdef undef +/* unsigned char *from: [max] */ +static BIGNUM *RSAref_bin2bn(unsigned char *from, BIGNUM *to, int max) + { + int i; + BIGNUM *ret; + + for (i=0; in=RSAref_bin2bn(from->m,NULL,RSAref_MAX_LEN); + to->e=RSAref_bin2bn(from->e,NULL,RSAref_MAX_LEN); + if ((to->n == NULL) || (to->e == NULL)) return(0); + return(1); + } +#endif + +static int RSAref_Public_eay2ref(RSA *from, R_RSA_PUBLIC_KEY *to) + { + to->bits=BN_num_bits(from->n); + if (!RSAref_bn2bin(from->n,to->modulus,MAX_RSA_MODULUS_LEN)) return(0); + if (!RSAref_bn2bin(from->e,to->exponent,MAX_RSA_MODULUS_LEN)) return(0); + return(1); + } + +#ifdef undef +static int RSAref_Private_ref2eay(RSArefPrivateKey *from, RSA *to) + { + if ((to->n=RSAref_bin2bn(from->m,NULL,RSAref_MAX_LEN)) == NULL) + return(0); + if ((to->e=RSAref_bin2bn(from->e,NULL,RSAref_MAX_LEN)) == NULL) + return(0); + if ((to->d=RSAref_bin2bn(from->d,NULL,RSAref_MAX_LEN)) == NULL) + return(0); + if ((to->p=RSAref_bin2bn(from->prime[0],NULL,RSAref_MAX_PLEN)) == NULL) + return(0); + if ((to->q=RSAref_bin2bn(from->prime[1],NULL,RSAref_MAX_PLEN)) == NULL) + return(0); + if ((to->dmp1=RSAref_bin2bn(from->pexp[0],NULL,RSAref_MAX_PLEN)) + == NULL) + return(0); + if ((to->dmq1=RSAref_bin2bn(from->pexp[1],NULL,RSAref_MAX_PLEN)) + == NULL) + return(0); + if ((to->iqmp=RSAref_bin2bn(from->coef,NULL,RSAref_MAX_PLEN)) == NULL) + return(0); + return(1); + } +#endif + +static int RSAref_Private_eay2ref(RSA *from, R_RSA_PRIVATE_KEY *to) + { + to->bits=BN_num_bits(from->n); + if (!RSAref_bn2bin(from->n,to->modulus,MAX_RSA_MODULUS_LEN)) return(0); + if (!RSAref_bn2bin(from->e,to->publicExponent,MAX_RSA_MODULUS_LEN)) return(0); + if (!RSAref_bn2bin(from->d,to->exponent,MAX_RSA_MODULUS_LEN)) return(0); + if (!RSAref_bn2bin(from->p,to->prime[0],MAX_RSA_PRIME_LEN)) return(0); + if (!RSAref_bn2bin(from->q,to->prime[1],MAX_RSA_PRIME_LEN)) return(0); + if (!RSAref_bn2bin(from->dmp1,to->primeExponent[0],MAX_RSA_PRIME_LEN)) return(0); + if (!RSAref_bn2bin(from->dmq1,to->primeExponent[1],MAX_RSA_PRIME_LEN)) return(0); + if (!RSAref_bn2bin(from->iqmp,to->coefficient,MAX_RSA_PRIME_LEN)) return(0); + return(1); + } + +static int rsaref_private_decrypt(int len, const unsigned char *from, unsigned char *to, + RSA *rsa, int padding) + { + int i,outlen= -1; + R_RSA_PRIVATE_KEY RSAkey; + + if (!RSAref_Private_eay2ref(rsa,&RSAkey)) + goto err; + if ((i=RSAPrivateDecrypt(to,(unsigned int *)&outlen,(unsigned char *)from,len,&RSAkey)) != 0) + { + RSAREFerr(RSAREF_F_RSAREF_PRIVATE_DECRYPT,i); + outlen= -1; + } +err: + memset(&RSAkey,0,sizeof(RSAkey)); + return(outlen); + } + +static int rsaref_private_encrypt(int len, const unsigned char *from, unsigned char *to, + RSA *rsa, int padding) + { + int i,outlen= -1; + R_RSA_PRIVATE_KEY RSAkey; + + if (padding != RSA_PKCS1_PADDING) + { + RSAREFerr(RSAREF_F_RSAREF_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + if (!RSAref_Private_eay2ref(rsa,&RSAkey)) + goto err; + if ((i=RSAPrivateEncrypt(to,(unsigned int *)&outlen,(unsigned char *)from,len,&RSAkey)) != 0) + { + RSAREFerr(RSAREF_F_RSAREF_PRIVATE_ENCRYPT,i); + outlen= -1; + } +err: + memset(&RSAkey,0,sizeof(RSAkey)); + return(outlen); + } + +static int rsaref_public_decrypt(int len, const unsigned char *from, unsigned char *to, + RSA *rsa, int padding) + { + int i,outlen= -1; + R_RSA_PUBLIC_KEY RSAkey; + + if (!RSAref_Public_eay2ref(rsa,&RSAkey)) + goto err; + if ((i=RSAPublicDecrypt(to,(unsigned int *)&outlen,(unsigned char *)from,len,&RSAkey)) != 0) + { + RSAREFerr(RSAREF_F_RSAREF_PUBLIC_DECRYPT,i); + outlen= -1; + } +err: + memset(&RSAkey,0,sizeof(RSAkey)); + return(outlen); + } + +static int rsaref_public_encrypt(int len, const unsigned char *from, unsigned char *to, + RSA *rsa, int padding) + { + int outlen= -1; + int i; + R_RSA_PUBLIC_KEY RSAkey; + R_RANDOM_STRUCT rnd; + unsigned char buf[16]; + + if (padding != RSA_PKCS1_PADDING && padding != RSA_SSLV23_PADDING) + { + RSAREFerr(RSAREF_F_RSAREF_PUBLIC_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + + R_RandomInit(&rnd); + R_GetRandomBytesNeeded((unsigned int *)&i,&rnd); + while (i > 0) + { + if (RAND_bytes(buf,16) <= 0) + goto err; + R_RandomUpdate(&rnd,buf,(unsigned int)((i>16)?16:i)); + i-=16; + } + + if (!RSAref_Public_eay2ref(rsa,&RSAkey)) + goto err; + if ((i=RSAPublicEncrypt(to,(unsigned int *)&outlen,(unsigned char *)from,len,&RSAkey,&rnd)) != 0) + { + RSAREFerr(RSAREF_F_RSAREF_PUBLIC_ENCRYPT,i); + outlen= -1; + goto err; + } +err: + memset(&RSAkey,0,sizeof(RSAkey)); + R_RandomFinal(&rnd); + memset(&rnd,0,sizeof(rnd)); + return(outlen); + } + +/***************************************************************************** + * Symetric cipher and digest function registrars + **/ +static int rsaref_ciphers(ENGINE *e, const EVP_CIPHER **cipher, + const int **nids, int nid) + { + int ok = 1; + if(!cipher) + { + /* We are returning a list of supported nids */ + *nids = rsaref_cipher_nids; + return (sizeof(rsaref_cipher_nids)-1)/sizeof(rsaref_cipher_nids[0]); + } + /* We are being asked for a specific cipher */ + switch (nid) + { + case NID_des_cbc: + *cipher = &cipher_des_cbc; break; + case NID_des_ede3_cbc: + *cipher = &cipher_des_ede3_cbc; break; + case NID_desx_cbc: + *cipher = &cipher_desx_cbc; break; + default: + ok = 0; + *cipher = NULL; + break; + } + return ok; + } +static int rsaref_digests(ENGINE *e, const EVP_MD **digest, + const int **nids, int nid) + { + int ok = 1; + if(!digest) + { + /* We are returning a list of supported nids */ + *nids = rsaref_digest_nids; + return (sizeof(rsaref_digest_nids)-1)/sizeof(rsaref_digest_nids[0]); + } + /* We are being asked for a specific digest */ + switch (nid) + { + case NID_md2: + *digest = &digest_md2; break; + case NID_md5: + *digest = &digest_md5; break; + default: + ok = 0; + *digest = NULL; + break; + } + return ok; + } + +/***************************************************************************** + * DES functions + **/ +#undef data +#define data(ctx) ((DES_CBC_CTX *)(ctx)->cipher_data) +static int cipher_des_cbc_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { + DES_CBCInit(data(ctx), (unsigned char *)key, (unsigned char *)iv, enc); + return 1; + } +static int cipher_des_cbc_code(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl) + { + int ret = DES_CBCUpdate(data(ctx), out, (unsigned char *)in, inl); + switch (ret) + { + case RE_LEN: + RSAREFerr(RSAREF_F_CIPHER_DES_CBC_CODE,RSAREF_R_LENGTH_NOT_BLOCK_ALIGNED); + break; + case 0: + break; + default: + RSAREFerr(RSAREF_F_CIPHER_DES_CBC_CODE,RSAREF_R_UNKNOWN_FAULT); + } + return !ret; + } +static int cipher_des_cbc_clean(EVP_CIPHER_CTX *ctx) + { + memset(data(ctx), 0, ctx->cipher->ctx_size); + return 1; + } + +#undef data +#define data(ctx) ((DES3_CBC_CTX *)(ctx)->cipher_data) +static int cipher_des_ede3_cbc_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { + DES3_CBCInit(data(ctx), (unsigned char *)key, (unsigned char *)iv, + enc); + return 1; + } +static int cipher_des_ede3_cbc_code(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl) + { + int ret = DES3_CBCUpdate(data(ctx), out, (unsigned char *)in, inl); + switch (ret) + { + case RE_LEN: + RSAREFerr(RSAREF_F_CIPHER_DES_CBC_CODE,RSAREF_R_LENGTH_NOT_BLOCK_ALIGNED); + break; + case 0: + break; + default: + RSAREFerr(RSAREF_F_CIPHER_DES_CBC_CODE,RSAREF_R_UNKNOWN_FAULT); + } + return !ret; + } +static int cipher_des_ede3_cbc_clean(EVP_CIPHER_CTX *ctx) + { + memset(data(ctx), 0, ctx->cipher->ctx_size); + return 1; + } + +#undef data +#define data(ctx) ((DESX_CBC_CTX *)(ctx)->cipher_data) +static int cipher_desx_cbc_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { + DESX_CBCInit(data(ctx), (unsigned char *)key, (unsigned char *)iv, + enc); + return 1; + } +static int cipher_desx_cbc_code(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl) + { + int ret = DESX_CBCUpdate(data(ctx), out, (unsigned char *)in, inl); + switch (ret) + { + case RE_LEN: + RSAREFerr(RSAREF_F_CIPHER_DES_CBC_CODE,RSAREF_R_LENGTH_NOT_BLOCK_ALIGNED); + break; + case 0: + break; + default: + RSAREFerr(RSAREF_F_CIPHER_DES_CBC_CODE,RSAREF_R_UNKNOWN_FAULT); + } + return !ret; + } +static int cipher_desx_cbc_clean(EVP_CIPHER_CTX *ctx) + { + memset(data(ctx), 0, ctx->cipher->ctx_size); + return 1; + } + +/***************************************************************************** + * MD functions + **/ +#undef data +#define data(ctx) ((MD2_CTX *)(ctx)->md_data) +static int digest_md2_init(EVP_MD_CTX *ctx) + { + MD2Init(data(ctx)); + return 1; + } +static int digest_md2_update(EVP_MD_CTX *ctx,const void *data, + unsigned long count) + { + MD2Update(data(ctx), (unsigned char *)data, (unsigned int)count); + return 1; + } +static int digest_md2_final(EVP_MD_CTX *ctx,unsigned char *md) + { + MD2Final(md, data(ctx)); + return 1; + } + +#undef data +#define data(ctx) ((MD5_CTX *)(ctx)->md_data) +static int digest_md5_init(EVP_MD_CTX *ctx) + { + MD5Init(data(ctx)); + return 1; + } +static int digest_md5_update(EVP_MD_CTX *ctx,const void *data, + unsigned long count) + { + MD5Update(data(ctx), (unsigned char *)data, (unsigned int)count); + return 1; + } +static int digest_md5_final(EVP_MD_CTX *ctx,unsigned char *md) + { + MD5Final(md, data(ctx)); + return 1; + } diff --git a/demos/engines/rsaref/rsaref.ec b/demos/engines/rsaref/rsaref.ec new file mode 100644 index 0000000..c690ae3 --- /dev/null +++ b/demos/engines/rsaref/rsaref.ec @@ -0,0 +1,8 @@ +# configuration file for util/mkerr.pl +# +# use like this: +# +# perl ../../../util/mkerr.pl -conf rsaref.ec \ +# -nostatic -staticloader -write *.c + +L RSAREF rsaref_err.h rsaref_err.c diff --git a/demos/engines/rsaref/rsaref_err.c b/demos/engines/rsaref/rsaref_err.c new file mode 100644 index 0000000..ceaf057 --- /dev/null +++ b/demos/engines/rsaref/rsaref_err.c @@ -0,0 +1,161 @@ +/* rsaref_err.c */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include +#include +#include "rsaref_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR +static ERR_STRING_DATA RSAREF_str_functs[]= + { +{ERR_PACK(0,RSAREF_F_BNREF_MOD_EXP,0), "BNREF_MOD_EXP"}, +{ERR_PACK(0,RSAREF_F_CIPHER_DES_CBC_CODE,0), "CIPHER_DES_CBC_CODE"}, +{ERR_PACK(0,RSAREF_F_RSAREF_BN2BIN,0), "RSAREF_BN2BIN"}, +{ERR_PACK(0,RSAREF_F_RSAREF_MOD_EXP,0), "RSAREF_MOD_EXP"}, +{ERR_PACK(0,RSAREF_F_RSAREF_PRIVATE_DECRYPT,0), "RSAREF_PRIVATE_DECRYPT"}, +{ERR_PACK(0,RSAREF_F_RSAREF_PRIVATE_ENCRYPT,0), "RSAREF_PRIVATE_ENCRYPT"}, +{ERR_PACK(0,RSAREF_F_RSAREF_PUBLIC_DECRYPT,0), "RSAREF_PUBLIC_DECRYPT"}, +{ERR_PACK(0,RSAREF_F_RSAREF_PUBLIC_ENCRYPT,0), "RSAREF_PUBLIC_ENCRYPT"}, +{ERR_PACK(0,RSAREF_F_RSA_BN2BIN,0), "RSA_BN2BIN"}, +{ERR_PACK(0,RSAREF_F_RSA_PRIVATE_DECRYPT,0), "RSA_PRIVATE_DECRYPT"}, +{ERR_PACK(0,RSAREF_F_RSA_PRIVATE_ENCRYPT,0), "RSA_PRIVATE_ENCRYPT"}, +{ERR_PACK(0,RSAREF_F_RSA_PUBLIC_DECRYPT,0), "RSA_PUBLIC_DECRYPT"}, +{ERR_PACK(0,RSAREF_F_RSA_PUBLIC_ENCRYPT,0), "RSA_PUBLIC_ENCRYPT"}, +{0,NULL} + }; + +static ERR_STRING_DATA RSAREF_str_reasons[]= + { +{RSAREF_R_CONTENT_ENCODING ,"content encoding"}, +{RSAREF_R_DATA ,"data"}, +{RSAREF_R_DIGEST_ALGORITHM ,"digest algorithm"}, +{RSAREF_R_ENCODING ,"encoding"}, +{RSAREF_R_ENCRYPTION_ALGORITHM ,"encryption algorithm"}, +{RSAREF_R_KEY ,"key"}, +{RSAREF_R_KEY_ENCODING ,"key encoding"}, +{RSAREF_R_LEN ,"len"}, +{RSAREF_R_LENGTH_NOT_BLOCK_ALIGNED ,"length not block aligned"}, +{RSAREF_R_MODULUS_LEN ,"modulus len"}, +{RSAREF_R_NEED_RANDOM ,"need random"}, +{RSAREF_R_PRIVATE_KEY ,"private key"}, +{RSAREF_R_PUBLIC_KEY ,"public key"}, +{RSAREF_R_SIGNATURE ,"signature"}, +{RSAREF_R_SIGNATURE_ENCODING ,"signature encoding"}, +{RSAREF_R_UNKNOWN_FAULT ,"unknown fault"}, +{0,NULL} + }; + +#endif + +#ifdef RSAREF_LIB_NAME +static ERR_STRING_DATA RSAREF_lib_name[]= + { +{0 ,RSAREF_LIB_NAME}, +{0,NULL} + }; +#endif + + +static int RSAREF_lib_error_code=0; +static int RSAREF_error_init=1; + +static void ERR_load_RSAREF_strings(void) + { + if (RSAREF_lib_error_code == 0) + RSAREF_lib_error_code=ERR_get_next_error_library(); + + if (RSAREF_error_init) + { + RSAREF_error_init=0; +#ifndef OPENSSL_NO_ERR + ERR_load_strings(RSAREF_lib_error_code,RSAREF_str_functs); + ERR_load_strings(RSAREF_lib_error_code,RSAREF_str_reasons); +#endif + +#ifdef RSAREF_LIB_NAME + RSAREF_lib_name->error = ERR_PACK(RSAREF_lib_error_code,0,0); + ERR_load_strings(0,RSAREF_lib_name); +#endif + } + } + +static void ERR_unload_RSAREF_strings(void) + { + if (RSAREF_error_init == 0) + { +#ifndef OPENSSL_NO_ERR + ERR_unload_strings(RSAREF_lib_error_code,RSAREF_str_functs); + ERR_unload_strings(RSAREF_lib_error_code,RSAREF_str_reasons); +#endif + +#ifdef RSAREF_LIB_NAME + ERR_unload_strings(0,RSAREF_lib_name); +#endif + RSAREF_error_init=1; + } + } + +static void ERR_RSAREF_error(int function, int reason, char *file, int line) + { + if (RSAREF_lib_error_code == 0) + RSAREF_lib_error_code=ERR_get_next_error_library(); + ERR_PUT_error(RSAREF_lib_error_code,function,reason,file,line); + } diff --git a/demos/engines/rsaref/rsaref_err.h b/demos/engines/rsaref/rsaref_err.h new file mode 100644 index 0000000..1975970 --- /dev/null +++ b/demos/engines/rsaref/rsaref_err.h @@ -0,0 +1,109 @@ +/* rsaref_err.h */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_RSAREF_ERR_H +#define HEADER_RSAREF_ERR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +static void ERR_load_RSAREF_strings(void); +static void ERR_unload_RSAREF_strings(void); +static void ERR_RSAREF_error(int function, int reason, char *file, int line); +#define RSAREFerr(f,r) ERR_RSAREF_error((f),(r),__FILE__,__LINE__) +/* Error codes for the RSAREF functions. */ + +/* Function codes. */ +#define RSAREF_F_BNREF_MOD_EXP 100 +#define RSAREF_F_CIPHER_DES_CBC_CODE 112 +#define RSAREF_F_RSAREF_BN2BIN 101 +#define RSAREF_F_RSAREF_MOD_EXP 102 +#define RSAREF_F_RSAREF_PRIVATE_DECRYPT 103 +#define RSAREF_F_RSAREF_PRIVATE_ENCRYPT 104 +#define RSAREF_F_RSAREF_PUBLIC_DECRYPT 105 +#define RSAREF_F_RSAREF_PUBLIC_ENCRYPT 106 +#define RSAREF_F_RSA_BN2BIN 107 +#define RSAREF_F_RSA_PRIVATE_DECRYPT 108 +#define RSAREF_F_RSA_PRIVATE_ENCRYPT 109 +#define RSAREF_F_RSA_PUBLIC_DECRYPT 110 +#define RSAREF_F_RSA_PUBLIC_ENCRYPT 111 + +/* Reason codes. */ +#define RSAREF_R_CONTENT_ENCODING 100 +#define RSAREF_R_DATA 101 +#define RSAREF_R_DIGEST_ALGORITHM 102 +#define RSAREF_R_ENCODING 103 +#define RSAREF_R_ENCRYPTION_ALGORITHM 104 +#define RSAREF_R_KEY 105 +#define RSAREF_R_KEY_ENCODING 106 +#define RSAREF_R_LEN 107 +#define RSAREF_R_LENGTH_NOT_BLOCK_ALIGNED 114 +#define RSAREF_R_MODULUS_LEN 108 +#define RSAREF_R_NEED_RANDOM 109 +#define RSAREF_R_PRIVATE_KEY 110 +#define RSAREF_R_PUBLIC_KEY 111 +#define RSAREF_R_SIGNATURE 112 +#define RSAREF_R_SIGNATURE_ENCODING 113 +#define RSAREF_R_UNKNOWN_FAULT 115 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/demos/engines/zencod/Makefile b/demos/engines/zencod/Makefile new file mode 100644 index 0000000..5b6a339 --- /dev/null +++ b/demos/engines/zencod/Makefile @@ -0,0 +1,114 @@ +LIBNAME= libzencod +SRC= hw_zencod.c +OBJ= hw_zencod.o +HEADER= hw_zencod.h + +CC= gcc +PIC= -fPIC +CFLAGS= -g -I../../../include $(PIC) -DENGINE_DYNAMIC_SUPPORT -DFLAT_INC +AR= ar r +RANLIB= ranlib + +LIB= $(LIBNAME).a +SHLIB= $(LIBNAME).so + +all: + @echo 'Please choose a system to build on:' + @echo '' + @echo 'tru64: Tru64 Unix, Digital Unix, Digital OSF/1' + @echo 'solaris: Solaris' + @echo 'irix: IRIX' + @echo 'hpux32: 32-bit HP/UX' + @echo 'hpux64: 64-bit HP/UX' + @echo 'aix: AIX' + @echo 'gnu: Generic GNU-based system (gcc and GNU ld)' + @echo '' + +FORCE.update: +update: FORCE.update + perl ../../../util/mkerr.pl -conf hw_zencod.ec \ + -nostatic -staticloader -write hw_zencod.c + +gnu: $(SHLIB).gnu +tru64: $(SHLIB).tru64 +solaris: $(SHLIB).solaris +irix: $(SHLIB).irix +hpux32: $(SHLIB).hpux32 +hpux64: $(SHLIB).hpux64 +aix: $(SHLIB).aix + +$(LIB): $(OBJ) + $(AR) $(LIB) $(OBJ) + - $(RANLIB) $(LIB) + +LINK_SO= \ + ld -r -o $(LIBNAME).o $$ALLSYMSFLAGS $(LIB) && \ + (nm -Pg $(LIBNAME).o | grep ' [BDT] ' | cut -f1 -d' ' > $(LIBNAME).exp; \ + $$SHAREDCMD $$SHAREDFLAGS -o $(SHLIB) $(LIBNAME).o -L ../../.. -lcrypto -lc) + +$(SHLIB).gnu: $(LIB) + ALLSYMSFLAGS='--whole-archive' \ + SHAREDFLAGS='-shared -Wl,-soname=$(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).gnu +$(SHLIB).tru64: $(LIB) + ALLSYMSFLAGS='-all' \ + SHAREDFLAGS='-shared' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).tru64 +$(SHLIB).solaris: $(LIB) + ALLSYMSFLAGS='-z allextract' \ + SHAREDFLAGS='-G -h $(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).solaris +$(SHLIB).irix: $(LIB) + ALLSYMSFLAGS='-all' \ + SHAREDFLAGS='-shared -Wl,-soname,$(SHLIB)' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).irix +$(SHLIB).hpux32: $(LIB) + ALLSYMSFLAGS='-Fl' \ + SHAREDFLAGS='+vnocompatwarnings -b -z +s +h $(SHLIB)' \ + SHAREDCMD='/usr/ccs/bin/ld'; \ + $(LINK_SO) + touch $(SHLIB).hpux32 +$(SHLIB).hpux64: $(LIB) + ALLSYMSFLAGS='+forceload' \ + SHAREDFLAGS='-b -z +h $(SHLIB)' \ + SHAREDCMD='/usr/ccs/bin/ld'; \ + $(LINK_SO) + touch $(SHLIB).hpux64 +$(SHLIB).aix: $(LIB) + ALLSYMSFLAGS='-bnogc' \ + SHAREDFLAGS='-G -bE:$(LIBNAME).exp -bM:SRE' \ + SHAREDCMD='$(CC)'; \ + $(LINK_SO) + touch $(SHLIB).aix + +depend: + sed -e '/^# DO NOT DELETE.*/,$$d' < Makefile > Makefile.tmp + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' >> Makefile.tmp + gcc -M $(CFLAGS) $(SRC) >> Makefile.tmp + perl ../../../util/clean-depend.pl < Makefile.tmp > Makefile.new + rm -f Makefile.tmp Makefile + mv Makefile.new Makefile + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +rsaref.o: ../../../include/openssl/asn1.h ../../../include/openssl/bio.h +rsaref.o: ../../../include/openssl/bn.h ../../../include/openssl/crypto.h +rsaref.o: ../../../include/openssl/dh.h ../../../include/openssl/dsa.h +rsaref.o: ../../../include/openssl/e_os2.h ../../../include/openssl/engine.h +rsaref.o: ../../../include/openssl/err.h ../../../include/openssl/lhash.h +rsaref.o: ../../../include/openssl/opensslconf.h +rsaref.o: ../../../include/openssl/opensslv.h +rsaref.o: ../../../include/openssl/ossl_typ.h ../../../include/openssl/rand.h +rsaref.o: ../../../include/openssl/rsa.h ../../../include/openssl/safestack.h +rsaref.o: ../../../include/openssl/stack.h ../../../include/openssl/symhacks.h +rsaref.o: ../../../include/openssl/ui.h rsaref.c rsaref_err.c rsaref_err.h +rsaref.o: source/des.h source/global.h source/md2.h source/md5.h source/rsa.h +rsaref.o: source/rsaref.h diff --git a/demos/engines/zencod/hw_zencod.c b/demos/engines/zencod/hw_zencod.c new file mode 100644 index 0000000..4234b93 --- /dev/null +++ b/demos/engines/zencod/hw_zencod.c @@ -0,0 +1,1739 @@ +/* crypto/engine/hw_zencod.c */ + /* Written by Fred Donnat (frederic.donnat@zencod.com) for "zencod" + * engine integration in order to redirect crypto computing on a crypto + * hardware accelerator zenssl32 ;-) + * + * Date : 25 jun 2002 + * Revision : 17 Ju7 2002 + * Version : zencod_engine-0.9.7 + */ + +/* ==================================================================== + * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + +/* ENGINE general include */ +#include +#include +#include +#include + +#ifndef OPENSSL_NO_HW +#ifndef OPENSSL_NO_HW_ZENCOD + +#ifdef FLAT_INC +# include "hw_zencod.h" +#else +# include "vendor_defns/hw_zencod.h" +#endif + +#define ZENCOD_LIB_NAME "zencod engine" +#include "hw_zencod_err.c" + +#define FAIL_TO_SOFTWARE -15 + +#define ZEN_LIBRARY "zenbridge" + +#if 0 +# define PERROR(s) perror(s) +# define CHEESE() fputs("## [ZenEngine] ## " __FUNCTION__ "\n", stderr) +#else +# define PERROR(s) +# define CHEESE() +#endif + + +/* Sorry ;) */ +#ifndef WIN32 +static inline void esrever ( unsigned char *d, int l ) +{ + for(;--l>0;--l,d++){*d^=*(d+l);*(d+l)^=*d;*d^=*(d+l);} +} + +static inline void ypcmem ( unsigned char *d, const unsigned char *s, int l ) +{ + for(d+=l;l--;)*--d=*s++; +} +#else +static __inline void esrever ( unsigned char *d, int l ) +{ + for(;--l>0;--l,d++){*d^=*(d+l);*(d+l)^=*d;*d^=*(d+l);} +} + +static __inline void ypcmem ( unsigned char *d, const unsigned char *s, int l ) +{ + for(d+=l;l--;)*--d=*s++; +} +#endif + + +#define BIGNUM2ZEN(n, bn) (ptr_zencod_init_number((n), \ + (unsigned long) ((bn)->top * BN_BITS2), \ + (unsigned char *) ((bn)->d))) + +#define ZEN_BITS(n, bytes) (ptr_zencod_bytes2bits((unsigned char *) (n), (unsigned long) (bytes))) +#define ZEN_BYTES(bits) (ptr_zencod_bits2bytes((unsigned long) (bits))) + + +/* Function for ENGINE detection and control */ +static int zencod_destroy ( ENGINE *e ) ; +static int zencod_init ( ENGINE *e ) ; +static int zencod_finish ( ENGINE *e ) ; +static int zencod_ctrl ( ENGINE *e, int cmd, long i, void *p, void (*f) () ) ; + +/* BIGNUM stuff */ +static int zencod_bn_mod_exp ( BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx ) ; + +/* RSA stuff */ +#ifndef OPENSSL_NO_RSA +static int RSA_zencod_rsa_mod_exp ( BIGNUM *r0, const BIGNUM *I, RSA *rsa ) ; +static int RSA_zencod_bn_mod_exp ( BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx ) ; +#endif + +/* DSA stuff */ +#ifndef OPENSSL_NO_DSA +static int DSA_zencod_bn_mod_exp ( DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx ) ; + +static DSA_SIG *DSA_zencod_do_sign ( const unsigned char *dgst, int dlen, DSA *dsa ) ; +static int DSA_zencod_do_verify ( const unsigned char *dgst, int dgst_len, DSA_SIG *sig, + DSA *dsa ) ; +#endif + +/* DH stuff */ +#ifndef OPENSSL_NO_DH +static int DH_zencod_bn_mod_exp ( const DH *dh, BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx ) ; +static int DH_zencod_generate_key ( DH *dh ) ; +static int DH_zencod_compute_key ( unsigned char *key, const BIGNUM *pub_key, DH *dh ) ; +#endif + +/* Rand stuff */ +static void RAND_zencod_seed ( const void *buf, int num ) ; +static int RAND_zencod_rand_bytes ( unsigned char *buf, int num ) ; +static int RAND_zencod_rand_status ( void ) ; + +/* Digest Stuff */ +static int engine_digests ( ENGINE *e, const EVP_MD **digest, const int **nids, int nid ) ; + +/* Cipher Stuff */ +static int engine_ciphers ( ENGINE *e, const EVP_CIPHER **cipher, const int **nids, int nid ) ; + + +#define ZENCOD_CMD_SO_PATH ENGINE_CMD_BASE +static const ENGINE_CMD_DEFN zencod_cmd_defns [ ] = +{ + { ZENCOD_CMD_SO_PATH, + "SO_PATH", + "Specifies the path to the 'zenbridge' shared library", + ENGINE_CMD_FLAG_STRING}, + { 0, NULL, NULL, 0 } +} ; + + +#ifndef OPENSSL_NO_RSA +/* Our internal RSA_METHOD specific to zencod ENGINE providing pointers to our function */ +static RSA_METHOD zencod_rsa = +{ + "ZENCOD RSA method", + NULL, + NULL, + NULL, + NULL, + RSA_zencod_rsa_mod_exp, + RSA_zencod_bn_mod_exp, + NULL, + NULL, + 0, + NULL, + NULL, + NULL +} ; +#endif + +#ifndef OPENSSL_NO_DSA +/* Our internal DSA_METHOD specific to zencod ENGINE providing pointers to our function */ +static DSA_METHOD zencod_dsa = +{ + "ZENCOD DSA method", + DSA_zencod_do_sign, + NULL, + DSA_zencod_do_verify, + NULL, + DSA_zencod_bn_mod_exp, + NULL, + NULL, + 0, + NULL +} ; +#endif + +#ifndef OPENSSL_NO_DH +/* Our internal DH_METHOD specific to zencod ENGINE providing pointers to our function */ +static DH_METHOD zencod_dh = +{ + "ZENCOD DH method", + DH_zencod_generate_key, + DH_zencod_compute_key, + DH_zencod_bn_mod_exp, + NULL, + NULL, + 0, + NULL +} ; +#endif + +/* Our internal RAND_meth specific to zencod ZNGINE providing pointers to our function */ +static RAND_METHOD zencod_rand = +{ + RAND_zencod_seed, + RAND_zencod_rand_bytes, + NULL, + NULL, + RAND_zencod_rand_bytes, + RAND_zencod_rand_status +} ; + + +/* Constants used when creating the ENGINE */ +static const char *engine_zencod_id = "zencod"; +static const char *engine_zencod_name = "ZENCOD hardware engine support"; + + +/* This internal function is used by ENGINE_zencod () and possibly by the + * "dynamic" ENGINE support too ;-) + */ +static int bind_helper ( ENGINE *e ) +{ + +#ifndef OPENSSL_NO_RSA + const RSA_METHOD *meth_rsa ; +#endif +#ifndef OPENSSL_NO_DSA + const DSA_METHOD *meth_dsa ; +#endif +#ifndef OPENSSL_NO_DH + const DH_METHOD *meth_dh ; +#endif + + const RAND_METHOD *meth_rand ; + + + if ( !ENGINE_set_id ( e, engine_zencod_id ) || + !ENGINE_set_name ( e, engine_zencod_name ) || +#ifndef OPENSSL_NO_RSA + !ENGINE_set_RSA ( e, &zencod_rsa ) || +#endif +#ifndef OPENSSL_NO_DSA + !ENGINE_set_DSA ( e, &zencod_dsa ) || +#endif +#ifndef OPENSSL_NO_DH + !ENGINE_set_DH ( e, &zencod_dh ) || +#endif + !ENGINE_set_RAND ( e, &zencod_rand ) || + + !ENGINE_set_destroy_function ( e, zencod_destroy ) || + !ENGINE_set_init_function ( e, zencod_init ) || + !ENGINE_set_finish_function ( e, zencod_finish ) || + !ENGINE_set_ctrl_function ( e, zencod_ctrl ) || + !ENGINE_set_cmd_defns ( e, zencod_cmd_defns ) || + !ENGINE_set_digests ( e, engine_digests ) || + !ENGINE_set_ciphers ( e, engine_ciphers ) ) { + return 0 ; + } + +#ifndef OPENSSL_NO_RSA + /* We know that the "PKCS1_SSLeay()" functions hook properly + * to the Zencod-specific mod_exp and mod_exp_crt so we use + * those functions. NB: We don't use ENGINE_openssl() or + * anything "more generic" because something like the RSAref + * code may not hook properly, and if you own one of these + * cards then you have the right to do RSA operations on it + * anyway! + */ + meth_rsa = RSA_PKCS1_SSLeay () ; + + zencod_rsa.rsa_pub_enc = meth_rsa->rsa_pub_enc ; + zencod_rsa.rsa_pub_dec = meth_rsa->rsa_pub_dec ; + zencod_rsa.rsa_priv_enc = meth_rsa->rsa_priv_enc ; + zencod_rsa.rsa_priv_dec = meth_rsa->rsa_priv_dec ; + /* meth_rsa->rsa_mod_exp */ + /* meth_rsa->bn_mod_exp */ + zencod_rsa.init = meth_rsa->init ; + zencod_rsa.finish = meth_rsa->finish ; +#endif + +#ifndef OPENSSL_NO_DSA + /* We use OpenSSL meth to supply what we don't provide ;-*) + */ + meth_dsa = DSA_OpenSSL () ; + + /* meth_dsa->dsa_do_sign */ + zencod_dsa.dsa_sign_setup = meth_dsa->dsa_sign_setup ; + /* meth_dsa->dsa_do_verify */ + zencod_dsa.dsa_mod_exp = meth_dsa->dsa_mod_exp ; + /* zencod_dsa.bn_mod_exp = meth_dsa->bn_mod_exp ; */ + zencod_dsa.init = meth_dsa->init ; + zencod_dsa.finish = meth_dsa->finish ; +#endif + +#ifndef OPENSSL_NO_DH + /* We use OpenSSL meth to supply what we don't provide ;-*) + */ + meth_dh = DH_OpenSSL () ; + + /* zencod_dh.generate_key = meth_dh->generate_key ; */ + /* zencod_dh.compute_key = meth_dh->compute_key ; */ + /* zencod_dh.bn_mod_exp = meth_dh->bn_mod_exp ; */ + zencod_dh.init = meth_dh->init ; + zencod_dh.finish = meth_dh->finish ; + +#endif + + /* We use OpenSSL (SSLeay) meth to supply what we don't provide ;-*) + */ + meth_rand = RAND_SSLeay () ; + + /* meth_rand->seed ; */ + /* zencod_rand.seed = meth_rand->seed ; */ + /* meth_rand->bytes ; */ + /* zencod_rand.bytes = meth_rand->bytes ; */ + zencod_rand.cleanup = meth_rand->cleanup ; + zencod_rand.add = meth_rand->add ; + /* meth_rand->pseudorand ; */ + /* zencod_rand.pseudorand = meth_rand->pseudorand ; */ + /* zencod_rand.status = meth_rand->status ; */ + /* meth_rand->status ; */ + + /* Ensure the zencod error handling is set up */ + ERR_load_ZENCOD_strings () ; + return 1 ; +} + + +/* As this is only ever called once, there's no need for locking + * (indeed - the lock will already be held by our caller!!!) + */ +static ENGINE *ENGINE_zencod ( void ) +{ + + ENGINE *eng = ENGINE_new () ; + + if ( !eng ) { + return NULL ; + } + if ( !bind_helper ( eng ) ) { + ENGINE_free ( eng ) ; + return NULL ; + } + + return eng ; +} + + +#ifdef ENGINE_DYNAMIC_SUPPORT +static +#endif +void ENGINE_load_zencod ( void ) +{ + /* Copied from eng_[openssl|dyn].c */ + ENGINE *toadd = ENGINE_zencod ( ) ; + if ( !toadd ) return ; + ENGINE_add ( toadd ) ; + ENGINE_free ( toadd ) ; + ERR_clear_error ( ) ; +} + + +/* This is a process-global DSO handle used for loading and unloading + * the ZENBRIDGE library. + * NB: This is only set (or unset) during an * init () or finish () call + * (reference counts permitting) and they're * operating with global locks, + * so this should be thread-safe * implicitly. + */ +static DSO *zencod_dso = NULL ; + +static t_zencod_test *ptr_zencod_test = NULL ; +static t_zencod_bytes2bits *ptr_zencod_bytes2bits = NULL ; +static t_zencod_bits2bytes *ptr_zencod_bits2bytes = NULL ; +static t_zencod_new_number *ptr_zencod_new_number = NULL ; +static t_zencod_init_number *ptr_zencod_init_number = NULL ; + +static t_zencod_rsa_mod_exp *ptr_zencod_rsa_mod_exp = NULL ; +static t_zencod_rsa_mod_exp_crt *ptr_zencod_rsa_mod_exp_crt = NULL ; +static t_zencod_dsa_do_sign *ptr_zencod_dsa_do_sign = NULL ; +static t_zencod_dsa_do_verify *ptr_zencod_dsa_do_verify = NULL ; +static t_zencod_dh_generate_key *ptr_zencod_dh_generate_key = NULL ; +static t_zencod_dh_compute_key *ptr_zencod_dh_compute_key = NULL ; +static t_zencod_rand_bytes *ptr_zencod_rand_bytes = NULL ; +static t_zencod_math_mod_exp *ptr_zencod_math_mod_exp = NULL ; + +static t_zencod_md5_init *ptr_zencod_md5_init = NULL ; +static t_zencod_md5_update *ptr_zencod_md5_update = NULL ; +static t_zencod_md5_do_final *ptr_zencod_md5_do_final = NULL ; +static t_zencod_sha1_init *ptr_zencod_sha1_init = NULL ; +static t_zencod_sha1_update *ptr_zencod_sha1_update = NULL ; +static t_zencod_sha1_do_final *ptr_zencod_sha1_do_final = NULL ; + +static t_zencod_xdes_cipher *ptr_zencod_xdes_cipher = NULL ; +static t_zencod_rc4_cipher *ptr_zencod_rc4_cipher = NULL ; + +/* These are the static string constants for the DSO file name and the function + * symbol names to bind to. + */ +static const char *ZENCOD_LIBNAME = ZEN_LIBRARY ; + +static const char *ZENCOD_Fct_0 = "test_device" ; +static const char *ZENCOD_Fct_1 = "zenbridge_bytes2bits" ; +static const char *ZENCOD_Fct_2 = "zenbridge_bits2bytes" ; +static const char *ZENCOD_Fct_3 = "zenbridge_new_number" ; +static const char *ZENCOD_Fct_4 = "zenbridge_init_number" ; + +static const char *ZENCOD_Fct_exp_1 = "zenbridge_rsa_mod_exp" ; +static const char *ZENCOD_Fct_exp_2 = "zenbridge_rsa_mod_exp_crt" ; +static const char *ZENCOD_Fct_dsa_1 = "zenbridge_dsa_do_sign" ; +static const char *ZENCOD_Fct_dsa_2 = "zenbridge_dsa_do_verify" ; +static const char *ZENCOD_Fct_dh_1 = "zenbridge_dh_generate_key" ; +static const char *ZENCOD_Fct_dh_2 = "zenbridge_dh_compute_key" ; +static const char *ZENCOD_Fct_rand_1 = "zenbridge_rand_bytes" ; +static const char *ZENCOD_Fct_math_1 = "zenbridge_math_mod_exp" ; + +static const char *ZENCOD_Fct_md5_1 = "zenbridge_md5_init" ; +static const char *ZENCOD_Fct_md5_2 = "zenbridge_md5_update" ; +static const char *ZENCOD_Fct_md5_3 = "zenbridge_md5_do_final" ; +static const char *ZENCOD_Fct_sha1_1 = "zenbridge_sha1_init" ; +static const char *ZENCOD_Fct_sha1_2 = "zenbridge_sha1_update" ; +static const char *ZENCOD_Fct_sha1_3 = "zenbridge_sha1_do_final" ; + +static const char *ZENCOD_Fct_xdes_1 = "zenbridge_xdes_cipher" ; +static const char *ZENCOD_Fct_rc4_1 = "zenbridge_rc4_cipher" ; + +/* Destructor (complements the "ENGINE_zencod ()" constructor) + */ +static int zencod_destroy (ENGINE *e ) +{ + + ERR_unload_ZENCOD_strings () ; + + return 1 ; +} + + +/* (de)initialisation functions. Control Function + */ +static int zencod_init ( ENGINE *e ) +{ + + t_zencod_test *ptr_0 ; + t_zencod_bytes2bits *ptr_1 ; + t_zencod_bits2bytes *ptr_2 ; + t_zencod_new_number *ptr_3 ; + t_zencod_init_number *ptr_4 ; + t_zencod_rsa_mod_exp *ptr_exp_1 ; + t_zencod_rsa_mod_exp_crt *ptr_exp_2 ; + t_zencod_dsa_do_sign *ptr_dsa_1 ; + t_zencod_dsa_do_verify *ptr_dsa_2 ; + t_zencod_dh_generate_key *ptr_dh_1 ; + t_zencod_dh_compute_key *ptr_dh_2 ; + t_zencod_rand_bytes *ptr_rand_1 ; + t_zencod_math_mod_exp *ptr_math_1 ; + t_zencod_md5_init *ptr_md5_1 ; + t_zencod_md5_update *ptr_md5_2 ; + t_zencod_md5_do_final *ptr_md5_3 ; + t_zencod_sha1_init *ptr_sha1_1 ; + t_zencod_sha1_update *ptr_sha1_2 ; + t_zencod_sha1_do_final *ptr_sha1_3 ; + t_zencod_xdes_cipher *ptr_xdes_1 ; + t_zencod_rc4_cipher *ptr_rc4_1 ; + + CHEESE () ; + + /* + * We Should add some tests for non NULL parameters or bad value !! + * Stuff to be done ... + */ + + if ( zencod_dso != NULL ) { + ZENCODerr ( ZENCOD_F_ZENCOD_INIT, ZENCOD_R_ALREADY_LOADED ) ; + goto err ; + } + /* Trying to load the Library "cryptozen" + */ + zencod_dso = DSO_load ( NULL, ZENCOD_LIBNAME, NULL, 0 ) ; + if ( zencod_dso == NULL ) { + ZENCODerr ( ZENCOD_F_ZENCOD_INIT, ZENCOD_R_DSO_FAILURE ) ; + goto err ; + } + + /* Trying to load Function from the Library + */ + if ( ! ( ptr_1 = (t_zencod_bytes2bits*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_1 ) ) || + ! ( ptr_2 = (t_zencod_bits2bytes*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_2 ) ) || + ! ( ptr_3 = (t_zencod_new_number*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_3 ) ) || + ! ( ptr_4 = (t_zencod_init_number*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_4 ) ) || + ! ( ptr_exp_1 = (t_zencod_rsa_mod_exp*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_exp_1 ) ) || + ! ( ptr_exp_2 = (t_zencod_rsa_mod_exp_crt*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_exp_2 ) ) || + ! ( ptr_dsa_1 = (t_zencod_dsa_do_sign*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_dsa_1 ) ) || + ! ( ptr_dsa_2 = (t_zencod_dsa_do_verify*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_dsa_2 ) ) || + ! ( ptr_dh_1 = (t_zencod_dh_generate_key*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_dh_1 ) ) || + ! ( ptr_dh_2 = (t_zencod_dh_compute_key*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_dh_2 ) ) || + ! ( ptr_rand_1 = (t_zencod_rand_bytes*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_rand_1 ) ) || + ! ( ptr_math_1 = (t_zencod_math_mod_exp*) DSO_bind_func ( zencod_dso, ZENCOD_Fct_math_1 ) ) || + ! ( ptr_0 = (t_zencod_test *) DSO_bind_func ( zencod_dso, ZENCOD_Fct_0 ) ) || + ! ( ptr_md5_1 = (t_zencod_md5_init *) DSO_bind_func ( zencod_dso, ZENCOD_Fct_md5_1 ) ) || + ! ( ptr_md5_2 = (t_zencod_md5_update *) DSO_bind_func ( zencod_dso, ZENCOD_Fct_md5_2 ) ) || + ! ( ptr_md5_3 = (t_zencod_md5_do_final *) DSO_bind_func ( zencod_dso, ZENCOD_Fct_md5_3 ) ) || + ! ( ptr_sha1_1 = (t_zencod_sha1_init *) DSO_bind_func ( zencod_dso, ZENCOD_Fct_sha1_1 ) ) || + ! ( ptr_sha1_2 = (t_zencod_sha1_update *) DSO_bind_func ( zencod_dso, ZENCOD_Fct_sha1_2 ) ) || + ! ( ptr_sha1_3 = (t_zencod_sha1_do_final *) DSO_bind_func ( zencod_dso, ZENCOD_Fct_sha1_3 ) ) || + ! ( ptr_xdes_1 = (t_zencod_xdes_cipher *) DSO_bind_func ( zencod_dso, ZENCOD_Fct_xdes_1 ) ) || + ! ( ptr_rc4_1 = (t_zencod_rc4_cipher *) DSO_bind_func ( zencod_dso, ZENCOD_Fct_rc4_1 ) ) ) { + + ZENCODerr ( ZENCOD_F_ZENCOD_INIT, ZENCOD_R_DSO_FAILURE ) ; + goto err ; + } + + /* The function from "cryptozen" Library have been correctly loaded so copy them + */ + ptr_zencod_test = ptr_0 ; + ptr_zencod_bytes2bits = ptr_1 ; + ptr_zencod_bits2bytes = ptr_2 ; + ptr_zencod_new_number = ptr_3 ; + ptr_zencod_init_number = ptr_4 ; + ptr_zencod_rsa_mod_exp = ptr_exp_1 ; + ptr_zencod_rsa_mod_exp_crt = ptr_exp_2 ; + ptr_zencod_dsa_do_sign = ptr_dsa_1 ; + ptr_zencod_dsa_do_verify = ptr_dsa_2 ; + ptr_zencod_dh_generate_key = ptr_dh_1 ; + ptr_zencod_dh_compute_key = ptr_dh_2 ; + ptr_zencod_rand_bytes = ptr_rand_1 ; + ptr_zencod_math_mod_exp = ptr_math_1 ; + ptr_zencod_test = ptr_0 ; + ptr_zencod_md5_init = ptr_md5_1 ; + ptr_zencod_md5_update = ptr_md5_2 ; + ptr_zencod_md5_do_final = ptr_md5_3 ; + ptr_zencod_sha1_init = ptr_sha1_1 ; + ptr_zencod_sha1_update = ptr_sha1_2 ; + ptr_zencod_sha1_do_final = ptr_sha1_3 ; + ptr_zencod_xdes_cipher = ptr_xdes_1 ; + ptr_zencod_rc4_cipher = ptr_rc4_1 ; + + /* We should peform a test to see if there is actually any unit runnig on the system ... + * Even if the cryptozen library is loaded the module coul not be loaded on the system ... + * For now we may just open and close the device !! + */ + + if ( ptr_zencod_test () != 0 ) { + ZENCODerr ( ZENCOD_F_ZENCOD_INIT, ZENCOD_R_UNIT_FAILURE ) ; + goto err ; + } + + return 1 ; +err : + if ( zencod_dso ) { + DSO_free ( zencod_dso ) ; + } + zencod_dso = NULL ; + ptr_zencod_bytes2bits = NULL ; + ptr_zencod_bits2bytes = NULL ; + ptr_zencod_new_number = NULL ; + ptr_zencod_init_number = NULL ; + ptr_zencod_rsa_mod_exp = NULL ; + ptr_zencod_rsa_mod_exp_crt = NULL ; + ptr_zencod_dsa_do_sign = NULL ; + ptr_zencod_dsa_do_verify = NULL ; + ptr_zencod_dh_generate_key = NULL ; + ptr_zencod_dh_compute_key = NULL ; + ptr_zencod_rand_bytes = NULL ; + ptr_zencod_math_mod_exp = NULL ; + ptr_zencod_test = NULL ; + ptr_zencod_md5_init = NULL ; + ptr_zencod_md5_update = NULL ; + ptr_zencod_md5_do_final = NULL ; + ptr_zencod_sha1_init = NULL ; + ptr_zencod_sha1_update = NULL ; + ptr_zencod_sha1_do_final = NULL ; + ptr_zencod_xdes_cipher = NULL ; + ptr_zencod_rc4_cipher = NULL ; + + return 0 ; +} + + +static int zencod_finish ( ENGINE *e ) +{ + + CHEESE () ; + + /* + * We Should add some tests for non NULL parameters or bad value !! + * Stuff to be done ... + */ + if ( zencod_dso == NULL ) { + ZENCODerr ( ZENCOD_F_ZENCOD_FINISH, ZENCOD_R_NOT_LOADED ) ; + return 0 ; + } + if ( !DSO_free ( zencod_dso ) ) { + ZENCODerr ( ZENCOD_F_ZENCOD_FINISH, ZENCOD_R_DSO_FAILURE ) ; + return 0 ; + } + + zencod_dso = NULL ; + + ptr_zencod_bytes2bits = NULL ; + ptr_zencod_bits2bytes = NULL ; + ptr_zencod_new_number = NULL ; + ptr_zencod_init_number = NULL ; + ptr_zencod_rsa_mod_exp = NULL ; + ptr_zencod_rsa_mod_exp_crt = NULL ; + ptr_zencod_dsa_do_sign = NULL ; + ptr_zencod_dsa_do_verify = NULL ; + ptr_zencod_dh_generate_key = NULL ; + ptr_zencod_dh_compute_key = NULL ; + ptr_zencod_rand_bytes = NULL ; + ptr_zencod_math_mod_exp = NULL ; + ptr_zencod_test = NULL ; + ptr_zencod_md5_init = NULL ; + ptr_zencod_md5_update = NULL ; + ptr_zencod_md5_do_final = NULL ; + ptr_zencod_sha1_init = NULL ; + ptr_zencod_sha1_update = NULL ; + ptr_zencod_sha1_do_final = NULL ; + ptr_zencod_xdes_cipher = NULL ; + ptr_zencod_rc4_cipher = NULL ; + + return 1 ; +} + + +static int zencod_ctrl ( ENGINE *e, int cmd, long i, void *p, void (*f) () ) +{ + + int initialised = ( ( zencod_dso == NULL ) ? 0 : 1 ) ; + + CHEESE () ; + + /* + * We Should add some tests for non NULL parameters or bad value !! + * Stuff to be done ... + */ + switch ( cmd ) { + case ZENCOD_CMD_SO_PATH : + if ( p == NULL ) { + ZENCODerr ( ZENCOD_F_ZENCOD_CTRL, ERR_R_PASSED_NULL_PARAMETER ) ; + return 0 ; + } + if ( initialised ) { + ZENCODerr ( ZENCOD_F_ZENCOD_CTRL, ZENCOD_R_ALREADY_LOADED ) ; + return 0 ; + } + ZENCOD_LIBNAME = (const char *) p ; + return 1 ; + default : + break ; + } + + ZENCODerr ( ZENCOD_F_ZENCOD_CTRL, ZENCOD_R_CTRL_COMMAND_NOT_IMPLEMENTED ) ; + + return 0 ; +} + + +/* BIGNUM stuff Functions + */ +static int zencod_bn_mod_exp ( BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx ) +{ + zen_nb_t y, x, e, n; + int ret; + + CHEESE () ; + + if ( !zencod_dso ) { + ENGINEerr(ZENCOD_F_ZENCOD_BN_MOD_EXP, ZENCOD_R_NOT_LOADED); + return 0; + } + + if ( !bn_wexpand(r, m->top + 1) ) { + ENGINEerr(ZENCOD_F_ZENCOD_BN_MOD_EXP, ZENCOD_R_BN_EXPAND_FAIL); + return 0; + } + + memset(r->d, 0, BN_num_bytes(m)); + + ptr_zencod_init_number ( &y, (r->dmax - 1) * sizeof (BN_ULONG) * 8, (unsigned char *) r->d ) ; + BIGNUM2ZEN ( &x, a ) ; + BIGNUM2ZEN ( &e, p ) ; + BIGNUM2ZEN ( &n, m ) ; + + /* Must invert x and e parameter due to BN mod exp prototype ... */ + ret = ptr_zencod_math_mod_exp ( &y, &e, &x, &n ) ; + + if ( ret ) { + PERROR("zenbridge_math_mod_exp"); + ENGINEerr(ZENCOD_F_ZENCOD_BN_MOD_EXP, ZENCOD_R_REQUEST_FAILED); + return 0; + } + + r->top = (BN_num_bits(m) + BN_BITS2 - 1) / BN_BITS2; + + return 1; +} + + +/* RSA stuff Functions + */ +#ifndef OPENSSL_NO_RSA +static int RSA_zencod_rsa_mod_exp ( BIGNUM *r0, const BIGNUM *i, RSA *rsa ) +{ + + CHEESE () ; + + if ( !zencod_dso ) { + ENGINEerr(ZENCOD_F_ZENCOD_RSA_MOD_EXP_CRT, ZENCOD_R_NOT_LOADED); + return 0; + } + + if ( !rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp ) { + ENGINEerr(ZENCOD_F_ZENCOD_RSA_MOD_EXP_CRT, ZENCOD_R_BAD_KEY_COMPONENTS); + return 0; + } + + /* Do in software if argument is too large for hardware */ + if ( RSA_size(rsa) * 8 > ZENBRIDGE_MAX_KEYSIZE_RSA_CRT ) { + const RSA_METHOD *meth; + + meth = RSA_PKCS1_SSLeay(); + return meth->rsa_mod_exp(r0, i, rsa); + } else { + zen_nb_t y, x, p, q, dmp1, dmq1, iqmp; + + if ( !bn_expand(r0, RSA_size(rsa) * 8) ) { + ENGINEerr(ZENCOD_F_ZENCOD_RSA_MOD_EXP_CRT, ZENCOD_R_BN_EXPAND_FAIL); + return 0; + } + r0->top = (RSA_size(rsa) * 8 + BN_BITS2 - 1) / BN_BITS2; + + BIGNUM2ZEN ( &x, i ) ; + BIGNUM2ZEN ( &y, r0 ) ; + BIGNUM2ZEN ( &p, rsa->p ) ; + BIGNUM2ZEN ( &q, rsa->q ) ; + BIGNUM2ZEN ( &dmp1, rsa->dmp1 ) ; + BIGNUM2ZEN ( &dmq1, rsa->dmq1 ) ; + BIGNUM2ZEN ( &iqmp, rsa->iqmp ) ; + + if ( ptr_zencod_rsa_mod_exp_crt ( &y, &x, &p, &q, &dmp1, &dmq1, &iqmp ) < 0 ) { + PERROR("zenbridge_rsa_mod_exp_crt"); + ENGINEerr(ZENCOD_F_ZENCOD_RSA_MOD_EXP_CRT, ZENCOD_R_REQUEST_FAILED); + return 0; + } + + return 1; + } +} + + +/* This function is aliased to RSA_mod_exp (with the mont stuff dropped). + */ +static int RSA_zencod_bn_mod_exp ( BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx ) +{ + + CHEESE () ; + + if ( !zencod_dso ) { + ENGINEerr(ZENCOD_F_ZENCOD_RSA_MOD_EXP, ZENCOD_R_NOT_LOADED); + return 0; + } + + /* Do in software if argument is too large for hardware */ + if ( BN_num_bits(m) > ZENBRIDGE_MAX_KEYSIZE_RSA ) { + const RSA_METHOD *meth; + + meth = RSA_PKCS1_SSLeay(); + return meth->bn_mod_exp(r, a, p, m, ctx, m_ctx); + } else { + zen_nb_t y, x, e, n; + + if ( !bn_expand(r, BN_num_bits(m)) ) { + ENGINEerr(ZENCOD_F_ZENCOD_RSA_MOD_EXP, ZENCOD_R_BN_EXPAND_FAIL); + return 0; + } + r->top = (BN_num_bits(m) + BN_BITS2 - 1) / BN_BITS2; + + BIGNUM2ZEN ( &x, a ) ; + BIGNUM2ZEN ( &y, r ) ; + BIGNUM2ZEN ( &e, p ) ; + BIGNUM2ZEN ( &n, m ) ; + + if ( ptr_zencod_rsa_mod_exp ( &y, &x, &n, &e ) < 0 ) { + PERROR("zenbridge_rsa_mod_exp"); + ENGINEerr(ZENCOD_F_ZENCOD_RSA_MOD_EXP, ZENCOD_R_REQUEST_FAILED); + return 0; + } + + return 1; + } +} +#endif /* !OPENSSL_NO_RSA */ + + +#ifndef OPENSSL_NO_DSA +/* DSA stuff Functions + */ +static DSA_SIG *DSA_zencod_do_sign ( const unsigned char *dgst, int dlen, DSA *dsa ) +{ + zen_nb_t p, q, g, x, y, r, s, data; + DSA_SIG *sig; + BIGNUM *bn_r = NULL; + BIGNUM *bn_s = NULL; + char msg[20]; + + CHEESE(); + + if ( !zencod_dso ) { + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_SIGN, ZENCOD_R_NOT_LOADED); + goto FAILED; + } + + if ( dlen > 160 ) { + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_SIGN, ZENCOD_R_REQUEST_FAILED); + goto FAILED; + } + + /* Do in software if argument is too large for hardware */ + if ( BN_num_bits(dsa->p) > ZENBRIDGE_MAX_KEYSIZE_DSA_SIGN || + BN_num_bits(dsa->g) > ZENBRIDGE_MAX_KEYSIZE_DSA_SIGN ) { + const DSA_METHOD *meth; + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_SIGN, ZENCOD_R_BAD_KEY_COMPONENTS); + meth = DSA_OpenSSL(); + return meth->dsa_do_sign(dgst, dlen, dsa); + } + + if ( !(bn_s = BN_new()) || !(bn_r = BN_new()) ) { + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_SIGN, ZENCOD_R_BAD_KEY_COMPONENTS); + goto FAILED; + } + + if ( !bn_expand(bn_r, 160) || !bn_expand(bn_s, 160) ) { + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_SIGN, ZENCOD_R_BN_EXPAND_FAIL); + goto FAILED; + } + + bn_r->top = bn_s->top = (160 + BN_BITS2 - 1) / BN_BITS2; + BIGNUM2ZEN ( &p, dsa->p ) ; + BIGNUM2ZEN ( &q, dsa->q ) ; + BIGNUM2ZEN ( &g, dsa->g ) ; + BIGNUM2ZEN ( &x, dsa->priv_key ) ; + BIGNUM2ZEN ( &y, dsa->pub_key ) ; + BIGNUM2ZEN ( &r, bn_r ) ; + BIGNUM2ZEN ( &s, bn_s ) ; + q.len = x.len = 160; + + ypcmem(msg, dgst, 20); + ptr_zencod_init_number ( &data, 160, msg ) ; + + if ( ptr_zencod_dsa_do_sign ( 0, &data, &y, &p, &q, &g, &x, &r, &s ) < 0 ) { + PERROR("zenbridge_dsa_do_sign"); + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_SIGN, ZENCOD_R_REQUEST_FAILED); + goto FAILED; + } + + if ( !( sig = DSA_SIG_new () ) ) { + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_SIGN, ZENCOD_R_REQUEST_FAILED); + goto FAILED; + } + sig->r = bn_r; + sig->s = bn_s; + return sig; + + FAILED: + if (bn_r) + BN_free(bn_r); + if (bn_s) + BN_free(bn_s); + return NULL; +} + + +static int DSA_zencod_do_verify ( const unsigned char *dgst, int dlen, DSA_SIG *sig, DSA *dsa ) +{ + zen_nb_t data, p, q, g, y, r, s, v; + char msg[20]; + char v_data[20]; + int ret; + + CHEESE(); + + if ( !zencod_dso ) { + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_VERIFY, ZENCOD_R_NOT_LOADED); + return 0; + } + + if ( dlen > 160 ) { + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_SIGN, ZENCOD_R_REQUEST_FAILED); + return 0; + } + + /* Do in software if argument is too large for hardware */ + if ( BN_num_bits(dsa->p) > ZENBRIDGE_MAX_KEYSIZE_DSA_SIGN || + BN_num_bits(dsa->g) > ZENBRIDGE_MAX_KEYSIZE_DSA_SIGN ) { + const DSA_METHOD *meth; + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_SIGN, ZENCOD_R_BAD_KEY_COMPONENTS); + meth = DSA_OpenSSL(); + return meth->dsa_do_verify(dgst, dlen, sig, dsa); + } + + BIGNUM2ZEN ( &p, dsa->p ) ; + BIGNUM2ZEN ( &q, dsa->q ) ; + BIGNUM2ZEN ( &g, dsa->g ) ; + BIGNUM2ZEN ( &y, dsa->pub_key ) ; + BIGNUM2ZEN ( &r, sig->r ) ; + BIGNUM2ZEN ( &s, sig->s ) ; + ptr_zencod_init_number ( &v, 160, v_data ) ; + ypcmem(msg, dgst, 20); + ptr_zencod_init_number ( &data, 160, msg ) ; + + if ( ( ret = ptr_zencod_dsa_do_verify ( 0, &data, &p, &q, &g, &y, &r, &s, &v ) ) < 0 ) { + PERROR("zenbridge_dsa_do_verify"); + ENGINEerr(ZENCOD_F_ZENCOD_DSA_DO_VERIFY, ZENCOD_R_REQUEST_FAILED); + return 0; + } + + return ( ( ret == 0 ) ? 1 : ret ) ; +} + + +static int DSA_zencod_bn_mod_exp ( DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *m_ctx ) +{ + CHEESE () ; + + return zencod_bn_mod_exp ( r, a, p, m, ctx ) ; +} +#endif /* !OPENSSL_NO_DSA */ + + +#ifndef OPENSSl_NO_DH +/* DH stuff Functions + */ +static int DH_zencod_generate_key ( DH *dh ) +{ + BIGNUM *bn_prv = NULL; + BIGNUM *bn_pub = NULL; + zen_nb_t y, x, g, p; + int generate_x; + + CHEESE(); + + if ( !zencod_dso ) { + ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_NOT_LOADED); + return 0; + } + + /* Private key */ + if ( dh->priv_key ) { + bn_prv = dh->priv_key; + generate_x = 0; + } else { + if (!(bn_prv = BN_new())) { + ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_BN_EXPAND_FAIL); + goto FAILED; + } + generate_x = 1; + } + + /* Public key */ + if ( dh->pub_key ) + bn_pub = dh->pub_key; + else + if ( !( bn_pub = BN_new () ) ) { + ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_BN_EXPAND_FAIL); + goto FAILED; + } + + /* Expand */ + if ( !bn_wexpand ( bn_prv, dh->p->dmax ) || + !bn_wexpand ( bn_pub, dh->p->dmax ) ) { + ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_BN_EXPAND_FAIL); + goto FAILED; + } + bn_prv->top = dh->p->top; + bn_pub->top = dh->p->top; + + /* Convert all keys */ + BIGNUM2ZEN ( &p, dh->p ) ; + BIGNUM2ZEN ( &g, dh->g ) ; + BIGNUM2ZEN ( &y, bn_pub ) ; + BIGNUM2ZEN ( &x, bn_prv ) ; + x.len = DH_size(dh) * 8; + + /* Adjust the lengths of P and G */ + p.len = ptr_zencod_bytes2bits ( p.data, ZEN_BYTES ( p.len ) ) ; + g.len = ptr_zencod_bytes2bits ( g.data, ZEN_BYTES ( g.len ) ) ; + + /* Send the request to the driver */ + if ( ptr_zencod_dh_generate_key ( &y, &x, &g, &p, generate_x ) < 0 ) { + perror("zenbridge_dh_generate_key"); + ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_REQUEST_FAILED); + goto FAILED; + } + + dh->priv_key = bn_prv; + dh->pub_key = bn_pub; + + return 1; + + FAILED: + if (!dh->priv_key && bn_prv) + BN_free(bn_prv); + if (!dh->pub_key && bn_pub) + BN_free(bn_pub); + + return 0; +} + + +static int DH_zencod_compute_key ( unsigned char *key, const BIGNUM *pub_key, DH *dh ) +{ + zen_nb_t y, x, p, k; + + CHEESE(); + + if ( !zencod_dso ) { + ENGINEerr(ZENCOD_F_ZENCOD_DH_COMPUTE, ZENCOD_R_NOT_LOADED); + return 0; + } + + if ( !dh->priv_key ) { + ENGINEerr(ZENCOD_F_ZENCOD_DH_COMPUTE, ZENCOD_R_BAD_KEY_COMPONENTS); + return 0; + } + + /* Convert all keys */ + BIGNUM2ZEN ( &y, pub_key ) ; + BIGNUM2ZEN ( &x, dh->priv_key ) ; + BIGNUM2ZEN ( &p, dh->p ) ; + ptr_zencod_init_number ( &k, p.len, key ) ; + + /* Adjust the lengths */ + p.len = ptr_zencod_bytes2bits ( p.data, ZEN_BYTES ( p.len ) ) ; + y.len = ptr_zencod_bytes2bits ( y.data, ZEN_BYTES ( y.len ) ) ; + x.len = ptr_zencod_bytes2bits ( x.data, ZEN_BYTES ( x.len ) ) ; + + /* Call the hardware */ + if ( ptr_zencod_dh_compute_key ( &k, &y, &x, &p ) < 0 ) { + ENGINEerr(ZENCOD_F_ZENCOD_DH_COMPUTE, ZENCOD_R_REQUEST_FAILED); + return 0; + } + + /* The key must be written MSB -> LSB */ + k.len = ptr_zencod_bytes2bits ( k.data, ZEN_BYTES ( k.len ) ) ; + esrever ( key, ZEN_BYTES ( k.len ) ) ; + + return ZEN_BYTES ( k.len ) ; +} + + +static int DH_zencod_bn_mod_exp ( const DH *dh, BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx ) +{ + CHEESE () ; + + return zencod_bn_mod_exp ( r, a, p, m, ctx ) ; +} +#endif /* !OPENSSL_NO_DH */ + + +/* RAND stuff Functions + */ +static void RAND_zencod_seed ( const void *buf, int num ) +{ + /* Nothing to do cause our crypto accelerator provide a true random generator */ +} + + +static int RAND_zencod_rand_bytes ( unsigned char *buf, int num ) +{ + zen_nb_t r; + + CHEESE(); + + if ( !zencod_dso ) { + ENGINEerr(ZENCOD_F_ZENCOD_RAND, ZENCOD_R_NOT_LOADED); + return 0; + } + + ptr_zencod_init_number ( &r, num * 8, buf ) ; + + if ( ptr_zencod_rand_bytes ( &r, ZENBRIDGE_RNG_DIRECT ) < 0 ) { + PERROR("zenbridge_rand_bytes"); + ENGINEerr(ZENCOD_F_ZENCOD_RAND, ZENCOD_R_REQUEST_FAILED); + return 0; + } + + return 1; +} + + +static int RAND_zencod_rand_status ( void ) +{ + CHEESE () ; + + return 1; +} + + +/* This stuff is needed if this ENGINE is being compiled into a self-contained + * shared-library. + */ +#ifdef ENGINE_DYNAMIC_SUPPORT +static int bind_fn ( ENGINE *e, const char *id ) +{ + + if ( id && ( strcmp ( id, engine_zencod_id ) != 0 ) ) { + return 0 ; + } + if ( !bind_helper ( e ) ) { + return 0 ; + } + + return 1 ; +} + +IMPLEMENT_DYNAMIC_CHECK_FN () +IMPLEMENT_DYNAMIC_BIND_FN ( bind_fn ) +#endif /* ENGINE_DYNAMIC_SUPPORT */ + + + + +/* + * Adding "Digest" and "Cipher" tools ... + * This is in development ... ;-) + * In orfer to code this, i refer to hw_openbsd_dev_crypto and openssl engine made by Geoff Thorpe (if i'm rigth), + * and evp, sha md5 definitions etc ... + */ +/* First add some include ... */ +#include +#include +#include +#include +#include + + +/* Some variables declaration ... */ +/* DONS: + * Disable symetric computation except DES and 3DES, but let part of the code + */ +/* static int engine_digest_nids [ ] = { NID_sha1, NID_md5 } ; */ +static int engine_digest_nids [ ] = { } ; +static int engine_digest_nids_num = 0 ; +/* static int engine_cipher_nids [ ] = { NID_rc4, NID_rc4_40, NID_des_cbc, NID_des_ede3_cbc } ; */ +static int engine_cipher_nids [ ] = { NID_des_cbc, NID_des_ede3_cbc } ; +static int engine_cipher_nids_num = 2 ; + + +/* Function prototype ... */ +/* SHA stuff */ +static int engine_sha1_init ( EVP_MD_CTX *ctx ) ; +static int engine_sha1_update ( EVP_MD_CTX *ctx, const void *data, unsigned long count ) ; +static int engine_sha1_final ( EVP_MD_CTX *ctx, unsigned char *md ) ; + +/* MD5 stuff */ +static int engine_md5_init ( EVP_MD_CTX *ctx ) ; +static int engine_md5_update ( EVP_MD_CTX *ctx, const void *data, unsigned long count ) ; +static int engine_md5_final ( EVP_MD_CTX *ctx, unsigned char *md ) ; + +static int engine_md_cleanup ( EVP_MD_CTX *ctx ) ; +static int engine_md_copy ( EVP_MD_CTX *to, const EVP_MD_CTX *from ) ; + + +/* RC4 Stuff */ +static int engine_rc4_init_key ( EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc ) ; +static int engine_rc4_cipher ( EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl ) ; + +/* DES Stuff */ +static int engine_des_init_key ( EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc ) ; +static int engine_des_cbc_cipher ( EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl ) ; + +/* 3DES Stuff */ +static int engine_des_ede3_init_key ( EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc ) ; +static int engine_des_ede3_cbc_cipher ( EVP_CIPHER_CTX *ctx, unsigned char *out,const unsigned char *in, unsigned int inl ) ; + +static int engine_cipher_cleanup ( EVP_CIPHER_CTX *ctx ) ; /* cleanup ctx */ + + +/* The one for SHA ... */ +static const EVP_MD engine_sha1_md = +{ + NID_sha1, + NID_sha1WithRSAEncryption, + SHA_DIGEST_LENGTH, + EVP_MD_FLAG_ONESHOT, + /* 0, */ /* EVP_MD_FLAG_ONESHOT = x0001 digest can only handle a single block + * XXX: set according to device info ... */ + engine_sha1_init, + engine_sha1_update, + engine_sha1_final, + engine_md_copy, /* dev_crypto_sha_copy */ + engine_md_cleanup, /* dev_crypto_sha_cleanup */ + EVP_PKEY_RSA_method, + SHA_CBLOCK, + /* sizeof ( EVP_MD * ) + sizeof ( SHA_CTX ) */ + sizeof ( ZEN_MD_DATA ) + /* sizeof ( MD_CTX_DATA ) The message digest data structure ... */ +} ; + +/* The one for MD5 ... */ +static const EVP_MD engine_md5_md = +{ + NID_md5, + NID_md5WithRSAEncryption, + MD5_DIGEST_LENGTH, + EVP_MD_FLAG_ONESHOT, + /* 0, */ /* EVP_MD_FLAG_ONESHOT = x0001 digest can only handle a single block + * XXX: set according to device info ... */ + engine_md5_init, + engine_md5_update, + engine_md5_final, + engine_md_copy, /* dev_crypto_md5_copy */ + engine_md_cleanup, /* dev_crypto_md5_cleanup */ + EVP_PKEY_RSA_method, + MD5_CBLOCK, + /* sizeof ( EVP_MD * ) + sizeof ( MD5_CTX ) */ + sizeof ( ZEN_MD_DATA ) + /* sizeof ( MD_CTX_DATA ) The message digest data structure ... */ +} ; + + +/* The one for RC4 ... */ +#define EVP_RC4_KEY_SIZE 16 + +/* Try something static ... */ +typedef struct +{ + unsigned int len ; + unsigned int first ; + unsigned char rc4_state [ 260 ] ; +} NEW_ZEN_RC4_KEY ; + +#define rc4_data(ctx) ( (EVP_RC4_KEY *) ( ctx )->cipher_data ) + +static const EVP_CIPHER engine_rc4 = +{ + NID_rc4, + 1, + 16, /* EVP_RC4_KEY_SIZE should be 128 bits */ + 0, /* FIXME: key should be up to 256 bytes */ + EVP_CIPH_VARIABLE_LENGTH, + engine_rc4_init_key, + engine_rc4_cipher, + engine_cipher_cleanup, + sizeof ( NEW_ZEN_RC4_KEY ), + NULL, + NULL, + NULL +} ; + +/* The one for RC4_40 ... */ +static const EVP_CIPHER engine_rc4_40 = +{ + NID_rc4_40, + 1, + 5, /* 40 bits */ + 0, + EVP_CIPH_VARIABLE_LENGTH, + engine_rc4_init_key, + engine_rc4_cipher, + engine_cipher_cleanup, + sizeof ( NEW_ZEN_RC4_KEY ), + NULL, + NULL, + NULL +} ; + +/* The one for DES ... */ + +/* Try something static ... */ +typedef struct +{ + unsigned char des_key [ 24 ] ; + unsigned char des_iv [ 8 ] ; +} ZEN_DES_KEY ; + +static const EVP_CIPHER engine_des_cbc = + { + NID_des_cbc, + 8, 8, 8, + 0 | EVP_CIPH_CBC_MODE, + engine_des_init_key, + engine_des_cbc_cipher, + engine_cipher_cleanup, + sizeof(ZEN_DES_KEY), + EVP_CIPHER_set_asn1_iv, + EVP_CIPHER_get_asn1_iv, + NULL, + NULL + }; + +/* The one for 3DES ... */ + +/* Try something static ... */ +typedef struct +{ + unsigned char des3_key [ 24 ] ; + unsigned char des3_iv [ 8 ] ; +} ZEN_3DES_KEY ; + +#define des_data(ctx) ( (DES_EDE_KEY *) ( ctx )->cipher_data ) + +static const EVP_CIPHER engine_des_ede3_cbc = + { + NID_des_ede3_cbc, + 8, 8, 8, + 0 | EVP_CIPH_CBC_MODE, + engine_des_ede3_init_key, + engine_des_ede3_cbc_cipher, + engine_cipher_cleanup, + sizeof(ZEN_3DES_KEY), + EVP_CIPHER_set_asn1_iv, + EVP_CIPHER_get_asn1_iv, + NULL, + NULL + }; + + +/* General function cloned on hw_openbsd_dev_crypto one ... */ +static int engine_digests ( ENGINE *e, const EVP_MD **digest, const int **nids, int nid ) +{ + +#ifdef DEBUG_ZENCOD_MD + fprintf ( stderr, "\t=>Function : static int engine_digests () called !\n" ) ; +#endif + + if ( !digest ) { + /* We are returning a list of supported nids */ + *nids = engine_digest_nids ; + return engine_digest_nids_num ; + } + /* We are being asked for a specific digest */ + if ( nid == NID_md5 ) { + *digest = &engine_md5_md ; + } + else if ( nid == NID_sha1 ) { + *digest = &engine_sha1_md ; + } + else { + *digest = NULL ; + return 0 ; + } + return 1 ; +} + + +/* SHA stuff Functions + */ +static int engine_sha1_init ( EVP_MD_CTX *ctx ) +{ + + int to_return = 0 ; + + /* Test with zenbridge library ... */ + to_return = ptr_zencod_sha1_init ( (ZEN_MD_DATA *) ctx->md_data ) ; + to_return = !to_return ; + + return to_return ; +} + + +static int engine_sha1_update ( EVP_MD_CTX *ctx, const void *data, unsigned long count ) +{ + + zen_nb_t input ; + int to_return = 0 ; + + /* Convert parameters ... */ + input.len = count ; + input.data = (unsigned char *) data ; + + /* Test with zenbridge library ... */ + to_return = ptr_zencod_sha1_update ( (ZEN_MD_DATA *) ctx->md_data, (const zen_nb_t *) &input ) ; + to_return = !to_return ; + + return to_return ; +} + + +static int engine_sha1_final ( EVP_MD_CTX *ctx, unsigned char *md ) +{ + + zen_nb_t output ; + int to_return = 0 ; + + /* Convert parameters ... */ + output.len = SHA_DIGEST_LENGTH ; + output.data = md ; + + /* Test with zenbridge library ... */ + to_return = ptr_zencod_sha1_do_final ( (ZEN_MD_DATA *) ctx->md_data, (zen_nb_t *) &output ) ; + to_return = !to_return ; + + return to_return ; +} + + + +/* MD5 stuff Functions + */ +static int engine_md5_init ( EVP_MD_CTX *ctx ) +{ + + int to_return = 0 ; + + /* Test with zenbridge library ... */ + to_return = ptr_zencod_md5_init ( (ZEN_MD_DATA *) ctx->md_data ) ; + to_return = !to_return ; + + return to_return ; +} + + +static int engine_md5_update ( EVP_MD_CTX *ctx, const void *data, unsigned long count ) +{ + + zen_nb_t input ; + int to_return = 0 ; + + /* Convert parameters ... */ + input.len = count ; + input.data = (unsigned char *) data ; + + /* Test with zenbridge library ... */ + to_return = ptr_zencod_md5_update ( (ZEN_MD_DATA *) ctx->md_data, (const zen_nb_t *) &input ) ; + to_return = !to_return ; + + return to_return ; +} + + +static int engine_md5_final ( EVP_MD_CTX *ctx, unsigned char *md ) +{ + + zen_nb_t output ; + int to_return = 0 ; + + /* Convert parameters ... */ + output.len = MD5_DIGEST_LENGTH ; + output.data = md ; + + /* Test with zenbridge library ... */ + to_return = ptr_zencod_md5_do_final ( (ZEN_MD_DATA *) ctx->md_data, (zen_nb_t *) &output ) ; + to_return = !to_return ; + + return to_return ; +} + + +static int engine_md_cleanup ( EVP_MD_CTX *ctx ) +{ + + ZEN_MD_DATA *zen_md_data = (ZEN_MD_DATA *) ctx->md_data ; + + if ( zen_md_data->HashBuffer != NULL ) { + OPENSSL_free ( zen_md_data->HashBuffer ) ; + zen_md_data->HashBufferSize = 0 ; + ctx->md_data = NULL ; + } + + return 1 ; +} + + +static int engine_md_copy ( EVP_MD_CTX *to, const EVP_MD_CTX *from ) +{ + const ZEN_MD_DATA *from_md = (ZEN_MD_DATA *) from->md_data ; + ZEN_MD_DATA *to_md = (ZEN_MD_DATA *) to->md_data ; + + to_md->HashBuffer = OPENSSL_malloc ( from_md->HashBufferSize ) ; + memcpy ( to_md->HashBuffer, from_md->HashBuffer, from_md->HashBufferSize ) ; + + return 1; +} + + +/* General function cloned on hw_openbsd_dev_crypto one ... */ +static int engine_ciphers ( ENGINE *e, const EVP_CIPHER **cipher, const int **nids, int nid ) +{ + + if ( !cipher ) { + /* We are returning a list of supported nids */ + *nids = engine_cipher_nids ; + return engine_cipher_nids_num ; + } + /* We are being asked for a specific cipher */ + if ( nid == NID_rc4 ) { + *cipher = &engine_rc4 ; + } + else if ( nid == NID_rc4_40 ) { + *cipher = &engine_rc4_40 ; + } + else if ( nid == NID_des_cbc ) { + *cipher = &engine_des_cbc ; + } + else if ( nid == NID_des_ede3_cbc ) { + *cipher = &engine_des_ede3_cbc ; + } + else { + *cipher = NULL ; + return 0 ; + } + + return 1 ; +} + + +static int engine_rc4_init_key ( EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc ) +{ + int to_return = 0 ; + int i = 0 ; + int nb = 0 ; + NEW_ZEN_RC4_KEY *tmp_rc4_key = NULL ; + + tmp_rc4_key = (NEW_ZEN_RC4_KEY *) ( ctx->cipher_data ) ; + tmp_rc4_key->first = 0 ; + tmp_rc4_key->len = ctx->key_len ; + tmp_rc4_key->rc4_state [ 0 ] = 0x00 ; + tmp_rc4_key->rc4_state [ 2 ] = 0x00 ; + nb = 256 / ctx->key_len ; + for ( i = 0; i < nb ; i++ ) { + memcpy ( &( tmp_rc4_key->rc4_state [ 4 + i*ctx->key_len ] ), key, ctx->key_len ) ; + } + + to_return = 1 ; + + return to_return ; +} + + +static int engine_rc4_cipher ( EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int in_len ) +{ + + zen_nb_t output, input ; + zen_nb_t rc4key ; + int to_return = 0 ; + NEW_ZEN_RC4_KEY *tmp_rc4_key = NULL ; + + /* Convert parameters ... */ + input.len = in_len ; + input.data = (unsigned char *) in ; + output.len = in_len ; + output.data = (unsigned char *) out ; + + tmp_rc4_key = ( (NEW_ZEN_RC4_KEY *) ( ctx->cipher_data ) ) ; + rc4key.len = 260 ; + rc4key.data = &( tmp_rc4_key->rc4_state [ 0 ] ) ; + + /* Test with zenbridge library ... */ + to_return = ptr_zencod_rc4_cipher ( &output, &input, (const zen_nb_t *) &rc4key, &( tmp_rc4_key->rc4_state [0] ), &( tmp_rc4_key->rc4_state [3] ), !tmp_rc4_key->first ) ; + to_return = !to_return ; + + /* Update encryption state ... */ + tmp_rc4_key->first = 1 ; + tmp_rc4_key = NULL ; + + return to_return ; +} + + +static int engine_des_init_key ( EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc ) +{ + + ZEN_DES_KEY *tmp_des_key = NULL ; + int to_return = 0 ; + + tmp_des_key = (ZEN_DES_KEY *) ( ctx->cipher_data ) ; + memcpy ( &( tmp_des_key->des_key [ 0 ] ), key, 8 ) ; + memcpy ( &( tmp_des_key->des_key [ 8 ] ), key, 8 ) ; + memcpy ( &( tmp_des_key->des_key [ 16 ] ), key, 8 ) ; + memcpy ( &( tmp_des_key->des_iv [ 0 ] ), iv, 8 ) ; + + to_return = 1 ; + + return to_return ; +} + + +static int engine_des_cbc_cipher ( EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl ) +{ + + zen_nb_t output, input ; + zen_nb_t deskey_1, deskey_2, deskey_3, iv ; + int to_return = 0 ; + + /* Convert parameters ... */ + input.len = inl ; + input.data = (unsigned char *) in ; + output.len = inl ; + output.data = out ; + + /* Set key parameters ... */ + deskey_1.len = 8 ; + deskey_2.len = 8 ; + deskey_3.len = 8 ; + deskey_1.data = (unsigned char *) ( (ZEN_DES_KEY *) ( ctx->cipher_data ) )->des_key ; + deskey_2.data = (unsigned char *) &( (ZEN_DES_KEY *) ( ctx->cipher_data ) )->des_key [ 8 ] ; + deskey_3.data = (unsigned char *) &( (ZEN_DES_KEY *) ( ctx->cipher_data ) )->des_key [ 16 ] ; + + /* Key correct iv ... */ + memcpy ( ( (ZEN_DES_KEY *) ( ctx->cipher_data ) )->des_iv, ctx->iv, 8 ) ; + iv.len = 8 ; + iv.data = (unsigned char *) ( (ZEN_DES_KEY *) ( ctx->cipher_data ) )->des_iv ; + + if ( ctx->encrypt == 0 ) { + memcpy ( ctx->iv, &( input.data [ input.len - 8 ] ), 8 ) ; + } + + /* Test with zenbridge library ... */ + to_return = ptr_zencod_xdes_cipher ( &output, &input, + (zen_nb_t *) &deskey_1, (zen_nb_t *) &deskey_2, (zen_nb_t *) &deskey_3, &iv, ctx->encrypt ) ; + to_return = !to_return ; + + /* But we need to set up the rigth iv ... + * Test ENCRYPT or DECRYPT mode to set iv ... */ + if ( ctx->encrypt == 1 ) { + memcpy ( ctx->iv, &( output.data [ output.len - 8 ] ), 8 ) ; + } + + return to_return ; +} + + +static int engine_des_ede3_init_key ( EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc ) +{ + + ZEN_3DES_KEY *tmp_3des_key = NULL ; + int to_return = 0 ; + + tmp_3des_key = (ZEN_3DES_KEY *) ( ctx->cipher_data ) ; + memcpy ( &( tmp_3des_key->des3_key [ 0 ] ), key, 24 ) ; + memcpy ( &( tmp_3des_key->des3_iv [ 0 ] ), iv, 8 ) ; + + to_return = 1; + + return to_return ; +} + + +static int engine_des_ede3_cbc_cipher ( EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, + unsigned int in_len ) +{ + + zen_nb_t output, input ; + zen_nb_t deskey_1, deskey_2, deskey_3, iv ; + int to_return = 0 ; + + /* Convert parameters ... */ + input.len = in_len ; + input.data = (unsigned char *) in ; + output.len = in_len ; + output.data = out ; + + /* Set key ... */ + deskey_1.len = 8 ; + deskey_2.len = 8 ; + deskey_3.len = 8 ; + deskey_1.data = (unsigned char *) ( (ZEN_3DES_KEY *) ( ctx->cipher_data ) )->des3_key ; + deskey_2.data = (unsigned char *) &( (ZEN_3DES_KEY *) ( ctx->cipher_data ) )->des3_key [ 8 ] ; + deskey_3.data = (unsigned char *) &( (ZEN_3DES_KEY *) ( ctx->cipher_data ) )->des3_key [ 16 ] ; + + /* Key correct iv ... */ + memcpy ( ( (ZEN_3DES_KEY *) ( ctx->cipher_data ) )->des3_iv, ctx->iv, 8 ) ; + iv.len = 8 ; + iv.data = (unsigned char *) ( (ZEN_3DES_KEY *) ( ctx->cipher_data ) )->des3_iv ; + + if ( ctx->encrypt == 0 ) { + memcpy ( ctx->iv, &( input.data [ input.len - 8 ] ), 8 ) ; + } + + /* Test with zenbridge library ... */ + to_return = ptr_zencod_xdes_cipher ( &output, &input, + (zen_nb_t *) &deskey_1, (zen_nb_t *) &deskey_2, (zen_nb_t *) &deskey_3, &iv, ctx->encrypt ) ; + to_return = !to_return ; + + if ( ctx->encrypt == 1 ) { + memcpy ( ctx->iv, &( output.data [ output.len - 8 ] ), 8 ) ; + } + + return to_return ; +} + + +static int engine_cipher_cleanup ( EVP_CIPHER_CTX *ctx ) +{ + + /* Set the key pointer ... */ + if ( ctx->cipher->nid == NID_rc4 || ctx->cipher->nid == NID_rc4_40 ) { + } + else if ( ctx->cipher->nid == NID_des_cbc ) { + } + else if ( ctx->cipher->nid == NID_des_ede3_cbc ) { + } + + return 1 ; +} + + +#endif /* !OPENSSL_NO_HW_ZENCOD */ +#endif /* !OPENSSL_NO_HW */ diff --git a/demos/engines/zencod/hw_zencod.ec b/demos/engines/zencod/hw_zencod.ec new file mode 100644 index 0000000..1552c79 --- /dev/null +++ b/demos/engines/zencod/hw_zencod.ec @@ -0,0 +1,8 @@ +# configuration file for util/mkerr.pl +# +# use like this: +# +# perl ../../../util/mkerr.pl -conf hw_zencod.ec \ +# -nostatic -staticloader -write *.c + +L ZENCOD hw_zencod_err.h hw_zencod_err.c diff --git a/demos/engines/zencod/hw_zencod.h b/demos/engines/zencod/hw_zencod.h new file mode 100644 index 0000000..415c9a6 --- /dev/null +++ b/demos/engines/zencod/hw_zencod.h @@ -0,0 +1,160 @@ +/* File : /crypto/engine/vendor_defns/hw_zencod.h */ +/* ==================================================================== + * Written by Donnat Frederic (frederic.donnat@zencod.com) from ZENCOD + * for "zencod" ENGINE integration in OpenSSL project. + */ + + + #ifndef _HW_ZENCOD_H_ +#define _HW_ZENCOD_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define ZENBRIDGE_MAX_KEYSIZE_RSA 2048 +#define ZENBRIDGE_MAX_KEYSIZE_RSA_CRT 1024 +#define ZENBRIDGE_MAX_KEYSIZE_DSA_SIGN 1024 +#define ZENBRIDGE_MAX_KEYSIZE_DSA_VRFY 1024 + +/* Library version computation */ +#define ZENBRIDGE_VERSION_MAJOR(x) (((x) >> 16) | 0xff) +#define ZENBRIDGE_VERSION_MINOR(x) (((x) >> 8) | 0xff) +#define ZENBRIDGE_VERSION_PATCH(x) (((x) >> 0) | 0xff) +#define ZENBRIDGE_VERSION(x, y, z) ((x) << 16 | (y) << 8 | (z)) + +/* + * Memory type + */ +typedef struct zencod_number_s { + unsigned long len; + unsigned char *data; +} zen_nb_t; + +#define KEY zen_nb_t + + +/* + * Misc + */ +typedef int t_zencod_lib_version (void); +typedef int t_zencod_hw_version (void); +typedef int t_zencod_test (void); +typedef int t_zencod_dump_key (FILE *stream, char *msg, KEY *key); + + +/* + * Key management tools + */ +typedef KEY *t_zencod_new_number (unsigned long len, unsigned char *data); +typedef int t_zencod_init_number (KEY *n, unsigned long len, unsigned char *data); +typedef unsigned long t_zencod_bytes2bits (unsigned char *n, unsigned long bytes); +typedef unsigned long t_zencod_bits2bytes (unsigned long bits); + + +/* + * RSA API + */ +/* Compute modular exponential : y = x**e | n */ +typedef int t_zencod_rsa_mod_exp (KEY *y, KEY *x, KEY *n, KEY *e); +/* Compute modular exponential : y1 = (x | p)**edp | p, y2 = (x | p)**edp | p, y = y2 + (qinv * (y1 - y2) | p) * q */ +typedef int t_zencod_rsa_mod_exp_crt (KEY *y, KEY *x, KEY *p, KEY *q, + KEY *edp, KEY *edq, KEY *qinv); + + +/* + * DSA API + */ +typedef int t_zencod_dsa_do_sign (unsigned int hash, KEY *data, KEY *random, + KEY *p, KEY *q, KEY *g, KEY *x, KEY *r, KEY *s); +typedef int t_zencod_dsa_do_verify (unsigned int hash, KEY *data, + KEY *p, KEY *q, KEY *g, KEY *y, + KEY *r, KEY *s, KEY *v); + + +/* + * DH API + */ + /* Key generation : compute public value y = g**x | n */ +typedef int t_zencod_dh_generate_key (KEY *y, KEY *x, KEY *g, KEY *n, int gen_x); +typedef int t_zencod_dh_compute_key (KEY *k, KEY *y, KEY *x, KEY *n); + + +/* + * RNG API + */ +#define ZENBRIDGE_RNG_DIRECT 0 +#define ZENBRIDGE_RNG_SHA1 1 +typedef int t_zencod_rand_bytes (KEY *rand, unsigned int flags); + + +/* + * Math API + */ +typedef int t_zencod_math_mod_exp (KEY *r, KEY *a, KEY *e, KEY *n); + + + + +/* + * Symetric API + */ +/* Define a data structure for digests operations */ +typedef struct ZEN_data_st +{ + unsigned int HashBufferSize ; + unsigned char *HashBuffer ; +} ZEN_MD_DATA ; + +/* + * Functions for Digest (MD5, SHA1) stuff + */ +/* output : output data buffer */ +/* input : input data buffer */ +/* algo : hash algorithm, MD5 or SHA1 */ +/* typedef int t_zencod_hash ( KEY *output, const KEY *input, int algo ) ; + * typedef int t_zencod_sha_hash ( KEY *output, const KEY *input, int algo ) ; + */ +/* For now separate this stuff that mad it easier to test */ +typedef int t_zencod_md5_init ( ZEN_MD_DATA *data ) ; +typedef int t_zencod_md5_update ( ZEN_MD_DATA *data, const KEY *input ) ; +typedef int t_zencod_md5_do_final ( ZEN_MD_DATA *data, KEY *output ) ; + +typedef int t_zencod_sha1_init ( ZEN_MD_DATA *data ) ; +typedef int t_zencod_sha1_update ( ZEN_MD_DATA *data, const KEY *input ) ; +typedef int t_zencod_sha1_do_final ( ZEN_MD_DATA *data, KEY *output ) ; + + +/* + * Functions for Cipher (RC4, DES, 3DES) stuff + */ +/* output : output data buffer */ +/* input : input data buffer */ +/* key : rc4 key data */ +/* index_1 : value of index x from RC4 key structure */ +/* index_2 : value of index y from RC4 key structure */ +/* Be carefull : RC4 key should be expanded before calling this method (Should we provide an expand function ??) */ +typedef int t_zencod_rc4_cipher ( KEY *output, const KEY *input, const KEY *key, + unsigned char *index_1, unsigned char *index_2, int mode ) ; + +/* output : output data buffer */ +/* input : input data buffer */ +/* key_1 : des first key data */ +/* key_2 : des second key data */ +/* key_3 : des third key data */ +/* iv : initial vector */ +/* mode : xdes mode (encrypt or decrypt) */ +/* Be carefull : In DES mode key_1 = key_2 = key_3 (as far as i can see !!) */ +typedef int t_zencod_xdes_cipher ( KEY *output, const KEY *input, const KEY *key_1, + const KEY *key_2, const KEY *key_3, const KEY *iv, int mode ) ; + + +#undef KEY + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !_HW_ZENCOD_H_ */ diff --git a/demos/engines/zencod/hw_zencod_err.c b/demos/engines/zencod/hw_zencod_err.c new file mode 100644 index 0000000..8ed0fff --- /dev/null +++ b/demos/engines/zencod/hw_zencod_err.c @@ -0,0 +1,151 @@ +/* hw_zencod_err.c */ +/* ==================================================================== + * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include +#include +#include "hw_zencod_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR +static ERR_STRING_DATA ZENCOD_str_functs[]= + { +{ERR_PACK(0,ZENCOD_F_ZENCOD_BN_MOD_EXP,0), "ZENCOD_BN_MOD_EXP"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_CTRL,0), "ZENCOD_CTRL"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_DH_COMPUTE,0), "ZENCOD_DH_COMPUTE"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_DH_GENERATE,0), "ZENCOD_DH_GENERATE"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_DSA_DO_SIGN,0), "ZENCOD_DSA_DO_SIGN"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_DSA_DO_VERIFY,0), "ZENCOD_DSA_DO_VERIFY"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_FINISH,0), "ZENCOD_FINISH"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_INIT,0), "ZENCOD_INIT"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_RAND,0), "ZENCOD_RAND"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_RSA_MOD_EXP,0), "ZENCOD_RSA_MOD_EXP"}, +{ERR_PACK(0,ZENCOD_F_ZENCOD_RSA_MOD_EXP_CRT,0), "ZENCOD_RSA_MOD_EXP_CRT"}, +{0,NULL} + }; + +static ERR_STRING_DATA ZENCOD_str_reasons[]= + { +{ZENCOD_R_ALREADY_LOADED ,"already loaded"}, +{ZENCOD_R_BAD_KEY_COMPONENTS ,"bad key components"}, +{ZENCOD_R_BN_EXPAND_FAIL ,"bn expand fail"}, +{ZENCOD_R_CTRL_COMMAND_NOT_IMPLEMENTED ,"ctrl command not implemented"}, +{ZENCOD_R_DSO_FAILURE ,"dso failure"}, +{ZENCOD_R_NOT_LOADED ,"not loaded"}, +{ZENCOD_R_REQUEST_FAILED ,"request failed"}, +{ZENCOD_R_UNIT_FAILURE ,"unit failure"}, +{0,NULL} + }; + +#endif + +#ifdef ZENCOD_LIB_NAME +static ERR_STRING_DATA ZENCOD_lib_name[]= + { +{0 ,ZENCOD_LIB_NAME}, +{0,NULL} + }; +#endif + + +static int ZENCOD_lib_error_code=0; +static int ZENCOD_error_init=1; + +static void ERR_load_ZENCOD_strings(void) + { + if (ZENCOD_lib_error_code == 0) + ZENCOD_lib_error_code=ERR_get_next_error_library(); + + if (ZENCOD_error_init) + { + ZENCOD_error_init=0; +#ifndef OPENSSL_NO_ERR + ERR_load_strings(ZENCOD_lib_error_code,ZENCOD_str_functs); + ERR_load_strings(ZENCOD_lib_error_code,ZENCOD_str_reasons); +#endif + +#ifdef ZENCOD_LIB_NAME + ZENCOD_lib_name->error = ERR_PACK(ZENCOD_lib_error_code,0,0); + ERR_load_strings(0,ZENCOD_lib_name); +#endif + } + } + +static void ERR_unload_ZENCOD_strings(void) + { + if (ZENCOD_error_init == 0) + { +#ifndef OPENSSL_NO_ERR + ERR_unload_strings(ZENCOD_lib_error_code,ZENCOD_str_functs); + ERR_unload_strings(ZENCOD_lib_error_code,ZENCOD_str_reasons); +#endif + +#ifdef ZENCOD_LIB_NAME + ERR_unload_strings(0,ZENCOD_lib_name); +#endif + ZENCOD_error_init=1; + } + } + +static void ERR_ZENCOD_error(int function, int reason, char *file, int line) + { + if (ZENCOD_lib_error_code == 0) + ZENCOD_lib_error_code=ERR_get_next_error_library(); + ERR_PUT_error(ZENCOD_lib_error_code,function,reason,file,line); + } diff --git a/demos/engines/zencod/hw_zencod_err.h b/demos/engines/zencod/hw_zencod_err.h new file mode 100644 index 0000000..60e923f --- /dev/null +++ b/demos/engines/zencod/hw_zencod_err.h @@ -0,0 +1,99 @@ +/* ==================================================================== + * Copyright (c) 2001-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_ZENCOD_ERR_H +#define HEADER_ZENCOD_ERR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +static void ERR_load_ZENCOD_strings(void); +static void ERR_unload_ZENCOD_strings(void); +static void ERR_ZENCOD_error(int function, int reason, char *file, int line); +#define ZENCODerr(f,r) ERR_ZENCOD_error((f),(r),__FILE__,__LINE__) + +/* Error codes for the ZENCOD functions. */ + +/* Function codes. */ +#define ZENCOD_F_ZENCOD_BN_MOD_EXP 100 +#define ZENCOD_F_ZENCOD_CTRL 101 +#define ZENCOD_F_ZENCOD_DH_COMPUTE 102 +#define ZENCOD_F_ZENCOD_DH_GENERATE 103 +#define ZENCOD_F_ZENCOD_DSA_DO_SIGN 104 +#define ZENCOD_F_ZENCOD_DSA_DO_VERIFY 105 +#define ZENCOD_F_ZENCOD_FINISH 106 +#define ZENCOD_F_ZENCOD_INIT 107 +#define ZENCOD_F_ZENCOD_RAND 108 +#define ZENCOD_F_ZENCOD_RSA_MOD_EXP 109 +#define ZENCOD_F_ZENCOD_RSA_MOD_EXP_CRT 110 + +/* Reason codes. */ +#define ZENCOD_R_ALREADY_LOADED 100 +#define ZENCOD_R_BAD_KEY_COMPONENTS 101 +#define ZENCOD_R_BN_EXPAND_FAIL 102 +#define ZENCOD_R_CTRL_COMMAND_NOT_IMPLEMENTED 103 +#define ZENCOD_R_DSO_FAILURE 104 +#define ZENCOD_R_NOT_LOADED 105 +#define ZENCOD_R_REQUEST_FAILED 106 +#define ZENCOD_R_UNIT_FAILURE 107 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/demos/maurice/Makefile b/demos/maurice/Makefile new file mode 100644 index 0000000..f9bf622 --- /dev/null +++ b/demos/maurice/Makefile @@ -0,0 +1,59 @@ +CC=cc +CFLAGS= -g -I../../include -Wall +LIBS= -L../.. -lcrypto +EXAMPLES=example1 example2 example3 example4 + +all: $(EXAMPLES) + +example1: example1.o loadkeys.o + $(CC) -o example1 example1.o loadkeys.o $(LIBS) + +example2: example2.o loadkeys.o + $(CC) -o example2 example2.o loadkeys.o $(LIBS) + +example3: example3.o + $(CC) -o example3 example3.o $(LIBS) + +example4: example4.o + $(CC) -o example4 example4.o $(LIBS) + +clean: + rm -f $(EXAMPLES) *.o + +test: all + @echo + @echo Example 1 Demonstrates the sealing and opening APIs + @echo Doing the encrypt side... + ./example1 t.t + @echo Doing the decrypt side... + ./example1 -d t.2 + diff t.2 README + rm -f t.t t.2 + @echo example1 is OK + + @echo + @echo Example2 Demonstrates rsa encryption and decryption + @echo and it should just print \"This the clear text\" + ./example2 + + @echo + @echo Example3 Demonstrates the use of symmetric block ciphers + @echo in this case it uses EVP_des_ede3_cbc + @echo i.e. triple DES in Cipher Block Chaining mode + @echo Doing the encrypt side... + ./example3 ThisIsThePassword t.t + @echo Doing the decrypt side... + ./example3 -d ThisIsThePassword t.2 + diff t.2 README + rm -f t.t t.2 + @echo example3 is OK + + @echo + @echo Example4 Demonstrates base64 encoding and decoding + @echo Doing the encrypt side... + ./example4 t.t + @echo Doing the decrypt side... + ./example4 -d t.2 + diff t.2 README + rm -f t.t t.2 + @echo example4 is OK diff --git a/demos/maurice/README b/demos/maurice/README new file mode 100644 index 0000000..29778d5 --- /dev/null +++ b/demos/maurice/README @@ -0,0 +1,34 @@ +From Maurice Gittens +-- + Example programs, demonstrating some basic SSLeay crypto library + operations, to help you not to make the same mistakes I did. + + The following files are present. + - loadkeys.c Demonstrates the loading and of public and + private keys. + - loadkeys.h The interface for loadkeys.c + - example1.c Demonstrates the sealing and opening API's + - example2.c Demonstrates rsa encryption and decryption + - example3.c Demonstrates the use of symmetric block ciphers + - example4.c Demonstrates base64 and decoding + - Makefile A makefile you probably will have to adjust for + your environment + - README this file + + + The programs were written by Maurice Gittens + with the necesary help from Eric Young + + You may do as you please with these programs, but please don't + pretend that you wrote them. + + To be complete: If you use these programs you acknowlegde that + you are aware that there is NO warranty of any kind associated + with these programs. I don't even claim that the programs work, + they are provided AS-IS. + + January 1997 + + Maurice + + diff --git a/demos/maurice/cert.pem b/demos/maurice/cert.pem new file mode 100644 index 0000000..e31a9ae --- /dev/null +++ b/demos/maurice/cert.pem @@ -0,0 +1,77 @@ +issuer :/C=NL/SP=Brabant/L=Eindhoven/O=Gittens Information Systems B.V./OU=Certification Services/CN=ca.gits.nl/Email=mgittens@gits.nl +subject:/C=NL/SP=Brabant/O=Gittens Information Systems B.V./OU=Certification Services/CN=caleb.gits.nl/Email=mgittens@gits.nl +serial :01 + +Certificate: + Data: + Version: 0 (0x0) + Serial Number: 1 (0x1) + Signature Algorithm: md5withRSAEncryption + Issuer: C=NL, SP=Brabant, L=Eindhoven, O=Gittens Information Systems B.V., OU=Certification Services, CN=ca.gits.nl/Email=mgittens@gits.nl + Validity + Not Before: Jan 5 13:21:16 1997 GMT + Not After : Jul 24 13:21:16 1997 GMT + Subject: C=NL, SP=Brabant, O=Gittens Information Systems B.V., OU=Certification Services, CN=caleb.gits.nl/Email=mgittens@gits.nl + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Modulus: + 00:dd:82:a0:fe:a9:8d:6a:02:7e:78:d6:33:75:9b: + 82:01:4b:12:80:ea:6b:9b:83:9e:e3:ae:dc:f3:d0: + 71:7c:4b:ea:03:57:b4:cc:ba:44:5b:b8:4b:49:d3: + f6:39:cc:3d:12:1f:da:58:26:27:bc:bc:ab:a4:6d: + 62:d1:91:5a:47:9f:80:40:c1:b9:fa:e3:1e:ef:52: + 78:46:26:43:65:1d:f2:6b:bf:ff:c0:81:66:14:cd: + 81:32:91:f1:f8:51:7d:0e:17:1f:27:fc:c7:51:fd: + 1c:73:41:e5:66:43:3c:67:a3:09:b9:5e:36:50:50: + b1:e8:42:bd:5c:c6:2b:ec:a9:2c:fe:6a:fe:40:26: + 64:9e:b9:bf:2d:1d:fb:d0:48:5b:82:2a:8e:ab:a4: + d5:7b:5f:26:84:8a:9a:69:5e:c1:71:e2:a9:59:4c: + 2a:76:f7:fd:f4:cf:3f:d3:ce:30:72:62:65:1c:e9: + e9:ee:d2:fc:44:00:1e:e0:80:57:e9:41:b3:f0:44: + e5:0f:77:3b:1a:1f:57:5e:94:1d:c3:a5:fa:af:41: + 8c:4c:30:6b:2b:00:84:52:0c:64:0c:a8:5b:17:16: + d1:1e:f8:ea:72:01:47:9a:b9:21:95:f9:71:ed:7c: + d2:93:54:0c:c5:9c:e8:e5:40:28:c5:a0:ca:b1:a9: + 20:f9 + Exponent: 65537 (0x10001) + Signature Algorithm: md5withRSAEncryption + 93:08:f9:e0:d4:c5:ca:95:de:4e:38:3b:28:87:e9:d3:b6:ce: + 4f:69:2e:c9:09:57:2f:fa:e2:50:9f:39:ec:f3:84:e8:3a:8f: + 9b:c3:06:62:90:49:93:6d:23:7a:2b:3d:7b:f9:46:32:18:d3: + 87:44:49:f7:29:2f:f3:58:97:70:c3:45:5b:90:52:1c:df:fb: + a8:a3:a1:29:53:a3:4c:ed:d2:51:d0:44:98:a4:14:6f:76:9d: + 0d:03:76:e5:d3:13:21:ce:a3:4d:2a:77:fe:ad:b3:47:6d:42: + b9:4a:0e:ff:61:f4:ec:62:b2:3b:00:9c:ac:16:a2:ec:19:c8: + c7:3d:d7:7d:97:cd:4d:1a:d2:00:07:4e:40:3d:b9:ba:1e:e2: + fe:81:28:57:b9:ad:2b:74:59:b0:9f:8b:a5:98:d3:75:06:67: + 4a:04:11:b2:ea:1a:8c:e0:d4:be:c8:0c:46:76:7f:5f:5a:7b: + 72:09:dd:b6:d3:6b:97:70:e8:7e:17:74:1c:f7:3a:5f:e3:fa: + c2:f7:95:bd:74:5e:44:4b:9b:bd:27:de:02:7f:87:1f:68:68: + 60:b9:f4:1d:2b:7b:ce:ef:b1:7f:3a:be:b9:66:60:54:6f:0c: + a0:dd:8c:03:a7:f1:9f:f8:0e:8d:bb:c6:ba:77:61:f7:8e:be: + 28:ba:d8:4f + +-----BEGIN CERTIFICATE----- +MIIDzzCCArcCAQEwDQYJKoZIhvcNAQEEBQAwgbUxCzAJBgNVBAYTAk5MMRAwDgYD +VQQIEwdCcmFiYW50MRIwEAYDVQQHEwlFaW5kaG92ZW4xKTAnBgNVBAoTIEdpdHRl +bnMgSW5mb3JtYXRpb24gU3lzdGVtcyBCLlYuMR8wHQYDVQQLExZDZXJ0aWZpY2F0 +aW9uIFNlcnZpY2VzMRMwEQYDVQQDEwpjYS5naXRzLm5sMR8wHQYJKoZIhvcNAQkB +FhBtZ2l0dGVuc0BnaXRzLm5sMB4XDTk3MDEwNTEzMjExNloXDTk3MDcyNDEzMjEx +NlowgaQxCzAJBgNVBAYTAk5MMRAwDgYDVQQIEwdCcmFiYW50MSkwJwYDVQQKEyBH +aXR0ZW5zIEluZm9ybWF0aW9uIFN5c3RlbXMgQi5WLjEfMB0GA1UECxMWQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlczEWMBQGA1UEAxMNY2FsZWIuZ2l0cy5ubDEfMB0GCSqG +SIb3DQEJARYQbWdpdHRlbnNAZ2l0cy5ubDCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAN2CoP6pjWoCfnjWM3WbggFLEoDqa5uDnuOu3PPQcXxL6gNXtMy6 +RFu4S0nT9jnMPRIf2lgmJ7y8q6RtYtGRWkefgEDBufrjHu9SeEYmQ2Ud8mu//8CB +ZhTNgTKR8fhRfQ4XHyf8x1H9HHNB5WZDPGejCbleNlBQsehCvVzGK+ypLP5q/kAm +ZJ65vy0d+9BIW4Iqjquk1XtfJoSKmmlewXHiqVlMKnb3/fTPP9POMHJiZRzp6e7S +/EQAHuCAV+lBs/BE5Q93OxofV16UHcOl+q9BjEwwaysAhFIMZAyoWxcW0R746nIB +R5q5IZX5ce180pNUDMWc6OVAKMWgyrGpIPkCAwEAATANBgkqhkiG9w0BAQQFAAOC +AQEAkwj54NTFypXeTjg7KIfp07bOT2kuyQlXL/riUJ857POE6DqPm8MGYpBJk20j +eis9e/lGMhjTh0RJ9ykv81iXcMNFW5BSHN/7qKOhKVOjTO3SUdBEmKQUb3adDQN2 +5dMTIc6jTSp3/q2zR21CuUoO/2H07GKyOwCcrBai7BnIxz3XfZfNTRrSAAdOQD25 +uh7i/oEoV7mtK3RZsJ+LpZjTdQZnSgQRsuoajODUvsgMRnZ/X1p7cgndttNrl3Do +fhd0HPc6X+P6wveVvXReREubvSfeAn+HH2hoYLn0HSt7zu+xfzq+uWZgVG8MoN2M +A6fxn/gOjbvGundh946+KLrYTw== +-----END CERTIFICATE----- + diff --git a/demos/maurice/example1.c b/demos/maurice/example1.c new file mode 100644 index 0000000..1ef8299 --- /dev/null +++ b/demos/maurice/example1.c @@ -0,0 +1,198 @@ +/* NOCW */ +/* + Please read the README file for condition of use, before + using this software. + + Maurice Gittens January 1997 +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "loadkeys.h" + +#define PUBFILE "cert.pem" +#define PRIVFILE "privkey.pem" + +#define STDIN 0 +#define STDOUT 1 + +void main_encrypt(void); +void main_decrypt(void); + +static const char *usage = "Usage: example1 [-d]\n"; + +int main(int argc, char *argv[]) +{ + + ERR_load_crypto_strings(); + + if ((argc == 1)) + { + main_encrypt(); + } + else if ((argc == 2) && !strcmp(argv[1],"-d")) + { + main_decrypt(); + } + else + { + printf("%s",usage); + exit(1); + } + + return 0; +} + +void main_encrypt(void) +{ + unsigned int ebuflen; + EVP_CIPHER_CTX ectx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char *ekey[1]; + int readlen; + int ekeylen, net_ekeylen; + EVP_PKEY *pubKey[1]; + char buf[512]; + char ebuf[512]; + + memset(iv, '\0', sizeof(iv)); + + pubKey[0] = ReadPublicKey(PUBFILE); + + if(!pubKey[0]) + { + fprintf(stderr,"Error: can't load public key"); + exit(1); + } + + ekey[0] = malloc(EVP_PKEY_size(pubKey[0])); + if (!ekey[0]) + { + EVP_PKEY_free(pubKey[0]); + perror("malloc"); + exit(1); + } + + EVP_SealInit(&ectx, + EVP_des_ede3_cbc(), + ekey, + &ekeylen, + iv, + pubKey, + 1); + + net_ekeylen = htonl(ekeylen); + write(STDOUT, (char*)&net_ekeylen, sizeof(net_ekeylen)); + write(STDOUT, ekey[0], ekeylen); + write(STDOUT, iv, sizeof(iv)); + + while(1) + { + readlen = read(STDIN, buf, sizeof(buf)); + + if (readlen <= 0) + { + if (readlen < 0) + perror("read"); + + break; + } + + EVP_SealUpdate(&ectx, ebuf, &ebuflen, buf, readlen); + + write(STDOUT, ebuf, ebuflen); + } + + EVP_SealFinal(&ectx, ebuf, &ebuflen); + + write(STDOUT, ebuf, ebuflen); + + EVP_PKEY_free(pubKey[0]); + free(ekey[0]); +} + +void main_decrypt(void) +{ + char buf[520]; + char ebuf[512]; + unsigned int buflen; + EVP_CIPHER_CTX ectx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char *encryptKey; + unsigned int ekeylen; + EVP_PKEY *privateKey; + + memset(iv, '\0', sizeof(iv)); + + privateKey = ReadPrivateKey(PRIVFILE); + if (!privateKey) + { + fprintf(stderr, "Error: can't load private key"); + exit(1); + } + + read(STDIN, &ekeylen, sizeof(ekeylen)); + ekeylen = ntohl(ekeylen); + + if (ekeylen != EVP_PKEY_size(privateKey)) + { + EVP_PKEY_free(privateKey); + fprintf(stderr, "keylength mismatch"); + exit(1); + } + + encryptKey = malloc(sizeof(char) * ekeylen); + if (!encryptKey) + { + EVP_PKEY_free(privateKey); + perror("malloc"); + exit(1); + } + + read(STDIN, encryptKey, ekeylen); + read(STDIN, iv, sizeof(iv)); + EVP_OpenInit(&ectx, + EVP_des_ede3_cbc(), + encryptKey, + ekeylen, + iv, + privateKey); + + while(1) + { + int readlen = read(STDIN, ebuf, sizeof(ebuf)); + + if (readlen <= 0) + { + if (readlen < 0) + perror("read"); + + break; + } + + EVP_OpenUpdate(&ectx, buf, &buflen, ebuf, readlen); + write(STDOUT, buf, buflen); + } + + EVP_OpenFinal(&ectx, buf, &buflen); + + write(STDOUT, buf, buflen); + + EVP_PKEY_free(privateKey); + free(encryptKey); +} + + diff --git a/demos/maurice/example2.c b/demos/maurice/example2.c new file mode 100644 index 0000000..57bce10 --- /dev/null +++ b/demos/maurice/example2.c @@ -0,0 +1,75 @@ +/* NOCW */ +/* + Please read the README file for condition of use, before + using this software. + + Maurice Gittens January 1997 +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "loadkeys.h" + +#define PUBFILE "cert.pem" +#define PRIVFILE "privkey.pem" +#define STDIN 0 +#define STDOUT 1 + +int main() +{ + char *ct = "This the clear text"; + char *buf; + char *buf2; + EVP_PKEY *pubKey; + EVP_PKEY *privKey; + int len; + + ERR_load_crypto_strings(); + + privKey = ReadPrivateKey(PRIVFILE); + if (!privKey) + { + ERR_print_errors_fp (stderr); + exit (1); + } + + pubKey = ReadPublicKey(PUBFILE); + if(!pubKey) + { + EVP_PKEY_free(privKey); + fprintf(stderr,"Error: can't load public key"); + exit(1); + } + + /* No error checking */ + buf = malloc(EVP_PKEY_size(pubKey)); + buf2 = malloc(EVP_PKEY_size(pubKey)); + + len = RSA_public_encrypt(strlen(ct)+1, ct, buf, pubKey->pkey.rsa,RSA_PKCS1_PADDING); + + if (len != EVP_PKEY_size(pubKey)) + { + fprintf(stderr,"Error: ciphertext should match length of key\n"); + exit(1); + } + + RSA_private_decrypt(len, buf, buf2, privKey->pkey.rsa,RSA_PKCS1_PADDING); + + printf("%s\n", buf2); + + EVP_PKEY_free(privKey); + EVP_PKEY_free(pubKey); + free(buf); + free(buf2); + return 0; +} diff --git a/demos/maurice/example3.c b/demos/maurice/example3.c new file mode 100644 index 0000000..03d8a20 --- /dev/null +++ b/demos/maurice/example3.c @@ -0,0 +1,87 @@ +/* NOCW */ +/* + Please read the README file for condition of use, before + using this software. + + Maurice Gittens January 1997 + +*/ + +#include +#include +#include +#include +#include + +#define STDIN 0 +#define STDOUT 1 +#define BUFLEN 512 +#define INIT_VECTOR "12345678" +#define ENCRYPT 1 +#define DECRYPT 0 +#define ALG EVP_des_ede3_cbc() + +static const char *usage = "Usage: example3 [-d] password\n"; + +void do_cipher(char *,int); + +int main(int argc, char *argv[]) +{ + if ((argc == 2)) + { + do_cipher(argv[1],ENCRYPT); + } + else if ((argc == 3) && !strcmp(argv[1],"-d")) + { + do_cipher(argv[2],DECRYPT); + } + else + { + fprintf(stderr,"%s", usage); + exit(1); + } + + return 0; +} + +void do_cipher(char *pw, int operation) +{ + char buf[BUFLEN]; + char ebuf[BUFLEN + 8]; + unsigned int ebuflen; /* rc; */ + unsigned char iv[EVP_MAX_IV_LENGTH], key[EVP_MAX_KEY_LENGTH]; + /* unsigned int ekeylen, net_ekeylen; */ + EVP_CIPHER_CTX ectx; + + memcpy(iv, INIT_VECTOR, sizeof(iv)); + + EVP_BytesToKey(ALG, EVP_md5(), "salu", pw, strlen(pw), 1, key, iv); + + EVP_CIPHER_CTX_init(&ectx); + EVP_CipherInit_ex(&ectx, ALG, NULL, key, iv, operation); + + while(1) + { + int readlen = read(STDIN, buf, sizeof(buf)); + + if (readlen <= 0) + { + if (!readlen) + break; + else + { + perror("read"); + exit(1); + } + } + + EVP_CipherUpdate(&ectx, ebuf, &ebuflen, buf, readlen); + + write(STDOUT, ebuf, ebuflen); + } + + EVP_CipherFinal_ex(&ectx, ebuf, &ebuflen); + EVP_CIPHER_CTX_cleanup(&ectx); + + write(STDOUT, ebuf, ebuflen); +} diff --git a/demos/maurice/example4.c b/demos/maurice/example4.c new file mode 100644 index 0000000..ce62984 --- /dev/null +++ b/demos/maurice/example4.c @@ -0,0 +1,123 @@ +/* NOCW */ +/* + Please read the README file for condition of use, before + using this software. + + Maurice Gittens January 1997 + +*/ + +#include +#include +#include +#include +#include + +#define STDIN 0 +#define STDOUT 1 +#define BUFLEN 512 + +static const char *usage = "Usage: example4 [-d]\n"; + +void do_encode(void); +void do_decode(void); + +int main(int argc, char *argv[]) +{ + if ((argc == 1)) + { + do_encode(); + } + else if ((argc == 2) && !strcmp(argv[1],"-d")) + { + do_decode(); + } + else + { + fprintf(stderr,"%s", usage); + exit(1); + } + + return 0; +} + +void do_encode() +{ + char buf[BUFLEN]; + char ebuf[BUFLEN+24]; + unsigned int ebuflen; + EVP_ENCODE_CTX ectx; + + EVP_EncodeInit(&ectx); + + while(1) + { + int readlen = read(STDIN, buf, sizeof(buf)); + + if (readlen <= 0) + { + if (!readlen) + break; + else + { + perror("read"); + exit(1); + } + } + + EVP_EncodeUpdate(&ectx, ebuf, &ebuflen, buf, readlen); + + write(STDOUT, ebuf, ebuflen); + } + + EVP_EncodeFinal(&ectx, ebuf, &ebuflen); + + write(STDOUT, ebuf, ebuflen); +} + +void do_decode() +{ + char buf[BUFLEN]; + char ebuf[BUFLEN+24]; + unsigned int ebuflen; + EVP_ENCODE_CTX ectx; + + EVP_DecodeInit(&ectx); + + while(1) + { + int readlen = read(STDIN, buf, sizeof(buf)); + int rc; + + if (readlen <= 0) + { + if (!readlen) + break; + else + { + perror("read"); + exit(1); + } + } + + rc = EVP_DecodeUpdate(&ectx, ebuf, &ebuflen, buf, readlen); + if (rc <= 0) + { + if (!rc) + { + write(STDOUT, ebuf, ebuflen); + break; + } + + fprintf(stderr, "Error: decoding message\n"); + return; + } + + write(STDOUT, ebuf, ebuflen); + } + + EVP_DecodeFinal(&ectx, ebuf, &ebuflen); + + write(STDOUT, ebuf, ebuflen); +} + diff --git a/demos/maurice/loadkeys.c b/demos/maurice/loadkeys.c new file mode 100644 index 0000000..82fd22a --- /dev/null +++ b/demos/maurice/loadkeys.c @@ -0,0 +1,72 @@ +/* NOCW */ +/* + Please read the README file for condition of use, before + using this software. + + Maurice Gittens January 1997 + +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +EVP_PKEY * ReadPublicKey(const char *certfile) +{ + FILE *fp = fopen (certfile, "r"); + X509 *x509; + EVP_PKEY *pkey; + + if (!fp) + return NULL; + + x509 = PEM_read_X509(fp, NULL, 0, NULL); + + if (x509 == NULL) + { + ERR_print_errors_fp (stderr); + return NULL; + } + + fclose (fp); + + pkey=X509_extract_key(x509); + + X509_free(x509); + + if (pkey == NULL) + ERR_print_errors_fp (stderr); + + return pkey; +} + +EVP_PKEY *ReadPrivateKey(const char *keyfile) +{ + FILE *fp = fopen(keyfile, "r"); + EVP_PKEY *pkey; + + if (!fp) + return NULL; + + pkey = PEM_read_PrivateKey(fp, NULL, 0, NULL); + + fclose (fp); + + if (pkey == NULL) + ERR_print_errors_fp (stderr); + + return pkey; +} + + diff --git a/demos/maurice/loadkeys.h b/demos/maurice/loadkeys.h new file mode 100644 index 0000000..d8fde86 --- /dev/null +++ b/demos/maurice/loadkeys.h @@ -0,0 +1,19 @@ +/* NOCW */ +/* + Please read the README file for condition of use, before + using this software. + + Maurice Gittens January 1997 + +*/ + +#ifndef LOADKEYS_H_SEEN +#define LOADKEYS_H_SEEN + +#include + +EVP_PKEY * ReadPublicKey(const char *certfile); +EVP_PKEY *ReadPrivateKey(const char *keyfile); + +#endif + diff --git a/demos/maurice/privkey.pem b/demos/maurice/privkey.pem new file mode 100644 index 0000000..fc3554e --- /dev/null +++ b/demos/maurice/privkey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA3YKg/qmNagJ+eNYzdZuCAUsSgOprm4Oe467c89BxfEvqA1e0 +zLpEW7hLSdP2Ocw9Eh/aWCYnvLyrpG1i0ZFaR5+AQMG5+uMe71J4RiZDZR3ya7// +wIFmFM2BMpHx+FF9DhcfJ/zHUf0cc0HlZkM8Z6MJuV42UFCx6EK9XMYr7Kks/mr+ +QCZknrm/LR370EhbgiqOq6TVe18mhIqaaV7BceKpWUwqdvf99M8/084wcmJlHOnp +7tL8RAAe4IBX6UGz8ETlD3c7Gh9XXpQdw6X6r0GMTDBrKwCEUgxkDKhbFxbRHvjq +cgFHmrkhlflx7XzSk1QMxZzo5UAoxaDKsakg+QIDAQABAoIBAQC0hnh083PnuJ6g +Flob+B+stCUhYWtPc6ZzgphaMD+9ABV4oescipWZdooNYiyikBwZgFIvUvFBtTXh +rLBDgUVlZ81beUb7/EvC2aBh818rsotWW0Sw/ARY4d7wetcL/EWBzUA8E5vR6wlb +uZGelR9OiyYqp2h2bj1/v5yaVnuHxBeBj5clTHtPMXc+/70iUNBDMZ0ruZTdSwll +e0DH8pp/5USYewlrKtRIJT7elC8LFMqEz4OpNvfaR2OEY0FatYYmSvQPNwV8/Eor +XlNzRi9qD0uXbVexaAgQZ3/KZuAzUbOgwJZZXEAOGkZ/J1n08jljPXdU0o7bHhNl +7siHbuEBAoGBAP53IvvJkhnH8Akf6E6sXelZkPKHnwDwfywDAiIhXza9DB1DViRS +bZUB5gzcxmLGalex5+LcwZmsqFO5NXZ8SQeE9p0YT8yJsX4J1w9JzSvsWJBS2vyW +Kbt21oG6JAGrWSGMIfxKpuahtWLf4JpGjftti0qIVQ60GKEPc1/xE2PZAoGBAN7Y +nRPaUaqcIwbnH9kovOKwZ/PWREy1ecr3YXj65VYTnwSJHD0+CJa/DX8eB/G4AoNA +Y2LPbq0Xu3+7SaUsO45VkaZuJmNwheUQ4tmyd/YdnVZ0AHXx1tvpR7QeO0WjnlNK +mR+x00fetrff2Ypahs0wtU0Xf3F8ORgVB8jnxBIhAoGAcwf0PpI+g30Im3dbEsWE +poogpiJ81HXjZ0fs3PTtD9eh9FCOTlkcxHFZR5M980TyqbX4t2tH8WpFpaNh8a/5 +a3bF7PoiiLnuDKXyHC0mnKZ42rU53VkcgGwWSAqXYFHPNwUcD+rHTBbp4kqGQ/eF +E5XPk9/RY5YyVAyiAUr/kvECgYBvW1Ua75SxqbZDI8mhbZ79tGMt0NtubZz/1KCL +oOxrGAD1dkJ7Q/1svunSpMIZgvcWeV1wqfFHY72ZNZC2jiTwmkffH9nlBPyTm92Q +JYOWo/PUmMEGLyRL3gWrtxOtV/as7nEYCndmyZ8KwTxmy5fi/z0J2f0gS5AIPbIX +LeGnoQKBgQDapjz9K4HWR5AMxyga4eiLIrmADySP846uz3eZIvTJQZ+6TAamvnno +KbnU21cGq5HBBtxqQvGswLPGW9rZAgykHHJmYBUp0xv4+I4qHfXyD7QNmvq+Vxjj +V2tgIafEpaf2ZsfM7BZeZz8MzeGcDwyrHtIO1FQiYN5Qz9Hq68XmVA== +-----END RSA PRIVATE KEY----- diff --git a/demos/pkcs12/README b/demos/pkcs12/README new file mode 100644 index 0000000..c87434b --- /dev/null +++ b/demos/pkcs12/README @@ -0,0 +1,3 @@ +PKCS#12 demo applications + +Written by Steve Henson. diff --git a/demos/pkcs12/pkread.c b/demos/pkcs12/pkread.c new file mode 100644 index 0000000..fa8f509 --- /dev/null +++ b/demos/pkcs12/pkread.c @@ -0,0 +1,61 @@ +/* pkread.c */ + +#include +#include +#include +#include +#include + +/* Simple PKCS#12 file reader */ + +int main(int argc, char **argv) +{ + FILE *fp; + EVP_PKEY *pkey; + X509 *cert; + STACK_OF(X509) *ca = NULL; + PKCS12 *p12; + int i; + if (argc != 4) { + fprintf(stderr, "Usage: pkread p12file password opfile\n"); + exit (1); + } + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + if (!(fp = fopen(argv[1], "rb"))) { + fprintf(stderr, "Error opening file %s\n", argv[1]); + exit(1); + } + p12 = d2i_PKCS12_fp(fp, NULL); + fclose (fp); + if (!p12) { + fprintf(stderr, "Error reading PKCS#12 file\n"); + ERR_print_errors_fp(stderr); + exit (1); + } + if (!PKCS12_parse(p12, argv[2], &pkey, &cert, &ca)) { + fprintf(stderr, "Error parsing PKCS#12 file\n"); + ERR_print_errors_fp(stderr); + exit (1); + } + PKCS12_free(p12); + if (!(fp = fopen(argv[3], "w"))) { + fprintf(stderr, "Error opening file %s\n", argv[1]); + exit(1); + } + if (pkey) { + fprintf(fp, "***Private Key***\n"); + PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL); + } + if (cert) { + fprintf(fp, "***User Certificate***\n"); + PEM_write_X509_AUX(fp, cert); + } + if (ca && sk_X509_num(ca)) { + fprintf(fp, "***Other Certificates***\n"); + for (i = 0; i < sk_X509_num(ca); i++) + PEM_write_X509_AUX(fp, sk_X509_value(ca, i)); + } + fclose(fp); + return 0; +} diff --git a/demos/pkcs12/pkwrite.c b/demos/pkcs12/pkwrite.c new file mode 100644 index 0000000..15f839d --- /dev/null +++ b/demos/pkcs12/pkwrite.c @@ -0,0 +1,46 @@ +/* pkwrite.c */ + +#include +#include +#include +#include +#include + +/* Simple PKCS#12 file creator */ + +int main(int argc, char **argv) +{ + FILE *fp; + EVP_PKEY *pkey; + X509 *cert; + PKCS12 *p12; + if (argc != 5) { + fprintf(stderr, "Usage: pkwrite infile password name p12file\n"); + exit(1); + } + SSLeay_add_all_algorithms(); + ERR_load_crypto_strings(); + if (!(fp = fopen(argv[1], "r"))) { + fprintf(stderr, "Error opening file %s\n", argv[1]); + exit(1); + } + cert = PEM_read_X509(fp, NULL, NULL, NULL); + rewind(fp); + pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); + fclose(fp); + p12 = PKCS12_create(argv[2], argv[3], pkey, cert, NULL, 0,0,0,0,0); + if(!p12) { + fprintf(stderr, "Error creating PKCS#12 structure\n"); + ERR_print_errors_fp(stderr); + exit(1); + } + if (!(fp = fopen(argv[4], "wb"))) { + fprintf(stderr, "Error opening file %s\n", argv[1]); + ERR_print_errors_fp(stderr); + exit(1); + } + i2d_PKCS12_fp(fp, p12); + PKCS12_free(p12); + fclose(fp); + return 0; +} diff --git a/demos/prime/Makefile b/demos/prime/Makefile new file mode 100644 index 0000000..0166cd4 --- /dev/null +++ b/demos/prime/Makefile @@ -0,0 +1,20 @@ +CC=cc +CFLAGS= -g -I../../include -Wall +LIBS= -L../.. -lcrypto +EXAMPLES=prime + +all: $(EXAMPLES) + +prime: prime.o + $(CC) -o prime prime.o $(LIBS) + +clean: + rm -f $(EXAMPLES) *.o + +test: all + @echo Test creating a 128-bit prime + ./prime 128 + @echo Test creating a 256-bit prime + ./prime 256 + @echo Test creating a 512-bit prime + ./prime 512 diff --git a/demos/prime/prime.c b/demos/prime/prime.c new file mode 100644 index 0000000..103e0ef --- /dev/null +++ b/demos/prime/prime.c @@ -0,0 +1,101 @@ +/* demos/prime/prime.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include + +void callback(type,num) +int type,num; + { + if (type == 0) + fprintf(stderr,"."); + else if (type == 1) + fprintf(stderr,"+"); + else if (type == 2) + fprintf(stderr,"*"); + fflush(stderr); + } + +int main(argc,argv) +int argc; +char *argv[]; + { + BIGNUM *rand; + int num=256; + + /* we should really call RAND_seed(char *bytes,int num); + * to fully initalise the random number generator */ + if (argc >= 2) + { + num=atoi(argv[1]); + if (num == 0) num=256; + } + + fprintf(stderr,"generate a strong prime\n"); + rand=BN_generate_prime(NULL,num,1,NULL,NULL,callback,NULL); + /* change the third parameter to 1 for a strong prime */ + fprintf(stderr,"\n"); + + BN_print_fp(stdout,rand); + fprintf(stdout,"\n"); + BN_free(rand); + exit(0); + return(0); + } + diff --git a/demos/privkey.pem b/demos/privkey.pem new file mode 100644 index 0000000..ddae240 --- /dev/null +++ b/demos/privkey.pem @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBPAIBAAJBAN+FmbxmHVOp/RxtpMGz0DvQEBz1sDktHp19hIoMSu0YZift5MAu +4xAEJYvWVCshDiyOTWsUBXwZkrkt87FyctkCAwEAAQJAG/vxBGpQb6IPo1iC0RF/ +F430BnwoBPCGLbeCOXpSgx5X+19vuTSdEqMgeNB6+aNb+XY/7mvVfCjyD6WZ0oxs +JQIhAPO+uL9cP40lFs62pdL3QSWsh3VNDByvOtr9LpeaxBm/AiEA6sKVfXsDQ5hd +SHt9U61r2r8Lcxmzi9Kw6JNqjMmzqWcCIQCKoRy+aZ8Tjdas9yDVHh+FZ90bEBkl +b1xQFNOdEj8aTQIhAOJWrO6INYNsWTPS6+hLYZtLamyUsQj0H+B8kNQge/mtAiEA +nBfvUl243qbqN8gF7Az1u33uc9FsPVvQPiBzLxZ4ixw= +-----END RSA PRIVATE KEY----- diff --git a/demos/selfsign.c b/demos/selfsign.c new file mode 100644 index 0000000..68904c6 --- /dev/null +++ b/demos/selfsign.c @@ -0,0 +1,180 @@ +/* NOCW */ +/* cc -o ssdemo -I../include selfsign.c ../libcrypto.a */ + +#include +#include + +#include +#include +#include + +int mkit(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days); + +int main() + { + BIO *bio_err; + X509 *x509=NULL; + EVP_PKEY *pkey=NULL; + + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + + bio_err=BIO_new_fp(stderr, BIO_NOCLOSE); + + mkit(&x509,&pkey,512,0,365); + + RSA_print_fp(stdout,pkey->pkey.rsa,0); + X509_print_fp(stdout,x509); + + PEM_write_PrivateKey(stdout,pkey,NULL,NULL,0,NULL, NULL); + PEM_write_X509(stdout,x509); + + X509_free(x509); + EVP_PKEY_free(pkey); + +#ifdef CUSTOM_EXT + /* Only needed if we add objects or custom extensions */ + X509V3_EXT_cleanup(); + OBJ_cleanup(); +#endif + + CRYPTO_mem_leaks(bio_err); + BIO_free(bio_err); + return(0); + } + +#ifdef WIN16 +# define MS_CALLBACK _far _loadds +# define MS_FAR _far +#else +# define MS_CALLBACK +# define MS_FAR +#endif + +static void MS_CALLBACK callback(p, n, arg) +int p; +int n; +void *arg; + { + char c='B'; + + if (p == 0) c='.'; + if (p == 1) c='+'; + if (p == 2) c='*'; + if (p == 3) c='\n'; + fputc(c,stderr); + } + +int mkit(x509p,pkeyp,bits,serial,days) +X509 **x509p; +EVP_PKEY **pkeyp; +int bits; +int serial; +int days; + { + X509 *x; + EVP_PKEY *pk; + RSA *rsa; + X509_NAME *name=NULL; + X509_NAME_ENTRY *ne=NULL; + X509_EXTENSION *ex=NULL; + + + if ((pkeyp == NULL) || (*pkeyp == NULL)) + { + if ((pk=EVP_PKEY_new()) == NULL) + { + abort(); + return(0); + } + } + else + pk= *pkeyp; + + if ((x509p == NULL) || (*x509p == NULL)) + { + if ((x=X509_new()) == NULL) + goto err; + } + else + x= *x509p; + + rsa=RSA_generate_key(bits,RSA_F4,callback,NULL); + if (!EVP_PKEY_assign_RSA(pk,rsa)) + { + abort(); + goto err; + } + rsa=NULL; + + X509_set_version(x,3); + ASN1_INTEGER_set(X509_get_serialNumber(x),serial); + X509_gmtime_adj(X509_get_notBefore(x),0); + X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days); + X509_set_pubkey(x,pk); + + name=X509_get_subject_name(x); + + /* This function creates and adds the entry, working out the + * correct string type and performing checks on its length. + * Normally we'd check the return value for errors... + */ + X509_NAME_add_entry_by_txt(name,"C", + MBSTRING_ASC, "UK", -1, -1, 0); + X509_NAME_add_entry_by_txt(name,"CN", + MBSTRING_ASC, "OpenSSL Group", -1, -1, 0); + + X509_set_issuer_name(x,name); + + /* Add extension using V3 code: we can set the config file as NULL + * because we wont reference any other sections. We can also set + * the context to NULL because none of these extensions below will need + * to access it. + */ + + ex = X509V3_EXT_conf_nid(NULL, NULL, NID_netscape_cert_type, "server"); + X509_add_ext(x,ex,-1); + X509_EXTENSION_free(ex); + + ex = X509V3_EXT_conf_nid(NULL, NULL, NID_netscape_comment, + "example comment extension"); + X509_add_ext(x,ex,-1); + X509_EXTENSION_free(ex); + + ex = X509V3_EXT_conf_nid(NULL, NULL, NID_netscape_ssl_server_name, + "www.openssl.org"); + + X509_add_ext(x,ex,-1); + X509_EXTENSION_free(ex); + +#if 0 + /* might want something like this too.... */ + ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, + "critical,CA:TRUE"); + + + X509_add_ext(x,ex,-1); + X509_EXTENSION_free(ex); +#endif + +#ifdef CUSTOM_EXT + /* Maybe even add our own extension based on existing */ + { + int nid; + nid = OBJ_create("1.2.3.4", "MyAlias", "My Test Alias Extension"); + X509V3_EXT_add_alias(nid, NID_netscape_comment); + ex = X509V3_EXT_conf_nid(NULL, NULL, nid, + "example comment alias"); + X509_add_ext(x,ex,-1); + X509_EXTENSION_free(ex); + } +#endif + + if (!X509_sign(x,pk,EVP_md5())) + goto err; + + *x509p=x; + *pkeyp=pk; + return(1); +err: + return(0); + } diff --git a/demos/sign/Makefile b/demos/sign/Makefile new file mode 100644 index 0000000..e6d391e --- /dev/null +++ b/demos/sign/Makefile @@ -0,0 +1,15 @@ +CC=cc +CFLAGS= -g -I../../include -Wall +LIBS= -L../.. -lcrypto +EXAMPLES=sign + +all: $(EXAMPLES) + +sign: sign.o + $(CC) -o sign sign.o $(LIBS) + +clean: + rm -f $(EXAMPLES) *.o + +test: all + ./sign diff --git a/demos/sign/cert.pem b/demos/sign/cert.pem new file mode 100644 index 0000000..9d7ac23 --- /dev/null +++ b/demos/sign/cert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD +VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv +bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy +dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X +DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw +EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l +dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT +EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp +MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw +L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN +BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX +9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4= +-----END CERTIFICATE----- diff --git a/demos/sign/key.pem b/demos/sign/key.pem new file mode 100644 index 0000000..239ad66 --- /dev/null +++ b/demos/sign/key.pem @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBPAIBAAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNwL4lYKbpzzlmC5beaQXeQ +2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAAQJBALjkK+jc2+iihI98riEF +oudmkNziSRTYjnwjx8mCoAjPWviB3c742eO3FG4/soi1jD9A5alihEOXfUzloenr +8IECIQD3B5+0l+68BA/6d76iUNqAAV8djGTzvxnCxycnxPQydQIhAMXt4trUI3nc +a+U8YL2HPFA3gmhBsSICbq2OptOCnM7hAiEA6Xi3JIQECob8YwkRj29DU3/4WYD7 +WLPgsQpwo1GuSpECICGsnWH5oaeD9t9jbFoSfhJvv0IZmxdcLpRcpslpeWBBAiEA +6/5B8J0GHdJq89FHwEG/H2eVVUYu5y/aD6sgcm+0Avg= +-----END RSA PRIVATE KEY----- diff --git a/demos/sign/sig.txt b/demos/sign/sig.txt new file mode 100644 index 0000000..5613c0e --- /dev/null +++ b/demos/sign/sig.txt @@ -0,0 +1,158 @@ +From ssl-lists-owner@mincom.com Mon Sep 30 02:37:40 1996 +Received: from cygnus.mincom.oz.au by orb.mincom.oz.au with SMTP id AA11782 + (5.65c/IDA-1.4.4 for eay); Mon, 30 Sep 1996 11:46:21 +1000 +Received: (from daemon@localhost) by cygnus.mincom.oz.au (8.7.5/8.7.3) id LAA18980 for ssl-users-outgoing; Mon, 30 Sep 1996 11:44:56 +1000 (EST) +Received: from minbne.mincom.oz.au (minbne.mincom.oz.au [192.55.196.247]) by cygnus.mincom.oz.au (8.7.5/8.7.3) with SMTP id LAA18962 for ; Mon, 30 Sep 1996 11:44:51 +1000 (EST) +Received: by minbne.mincom.oz.au id AA22230 + (5.65c/IDA-1.4.4 for ssl-users@listserv.mincom.oz.au); Mon, 30 Sep 1996 11:38:41 +1000 +Received: from brutus.neuronio.pt (brutus.neuronio.pt [193.126.253.2]) by bunyip.cc.uq.oz.au (8.7.6/8.7.3) with SMTP id LAA15824 for ; Mon, 30 Sep 1996 11:40:07 +1000 +Received: (from sampo@localhost) by brutus.neuronio.pt (8.6.11/8.6.11) id BAA08729; Mon, 30 Sep 1996 01:37:40 +0100 +Date: Mon, 30 Sep 1996 01:37:40 +0100 +Message-Id: <199609300037.BAA08729@brutus.neuronio.pt> +From: Sampo Kellomaki +To: ssl-users@mincom.com +Cc: sampo@brutus.neuronio.pt +Subject: Signing with envelope routines +Sender: ssl-lists-owner@mincom.com +Precedence: bulk +Status: RO +X-Status: D + + +I have been trying to figure out how to produce signatures with EVP_ +routines. I seem to be able to read in private key and sign some +data ok, but I can't figure out how I am supposed to read in +public key so that I could verify my signature. I use self signed +certificate. + +I figured I should use + EVP_PKEY* pkey = PEM_ASN1_read(d2i_PrivateKey, PEM_STRING_EVP_PKEY, + fp, NULL, NULL); +to read in private key and this seems to work Ok. + +However when I try analogous + EVP_PKEY* pkey = PEM_ASN1_read(d2i_PublicKey, PEM_STRING_X509, + fp, NULL, NULL); +the program fails with + +error:0D09508D:asn1 encoding routines:D2I_PUBLICKEY:unknown public key type:d2i_pu.c:93 +error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:pem_lib.c:232 + +I figured that the second argument to PEM_ASN1_read should match the +name in my PEM encoded object, hence PEM_STRING_X509. +PEM_STRING_EVP_PKEY seems to be somehow magical +because it matches whatever private key there happens to be. I could +not find a similar constant to use with getting the certificate, however. + +Is my approach of using PEM_ASN1_read correct? What should I pass in +as name? Can I use normal (or even self signed) X509 certificate for +verifying the signature? + +When will SSLeay documentation be written ;-)? If I would contribute +comments to the code, would Eric take time to review them and include +them in distribution? + +I'm using SSLeay-0.6.4. My program is included below along with the +key and cert that I use. + +--Sampo + +----------------------------------- +/* sign-it.cpp - Simple test app using SSLeay envelopes to sign data + 29.9.1996, Sampo Kellomaki */ + +#include +#include "rsa.h" +#include "evp.h" +#include "objects.h" +#include "x509.h" +#include "err.h" +#include "pem.h" +#include "ssl.h" + +void main () +{ + int err; + int sig_len; + unsigned char sig_buf [4096]; + const char certfile[] = "plain-cert.pem"; + const char keyfile[] = "plain-key.pem"; + const char data[] = "I owe you..."; + EVP_MD_CTX md_ctx; + EVP_PKEY* pkey; + FILE* fp; + + SSL_load_error_strings(); + + /* Read private key */ + + fp = fopen (keyfile, "r"); if (fp == NULL) exit (1); + pkey = (EVP_PKEY*)PEM_ASN1_read ((char *(*)())d2i_PrivateKey, + PEM_STRING_EVP_PKEY, + fp, + NULL, NULL); + if (pkey == NULL) { ERR_print_errors_fp (stderr); exit (1); } + fclose (fp); + + /* Do the signature */ + + EVP_SignInit (&md_ctx, EVP_md5()); + EVP_SignUpdate (&md_ctx, data, strlen(data)); + sig_len = sizeof(sig_buf); + err = EVP_SignFinal (&md_ctx, + sig_buf, + &sig_len, + pkey); + if (err != 1) { ERR_print_errors_fp (stderr); exit (1); } + EVP_PKEY_free (pkey); + + /* Read public key */ + + fp = fopen (certfile, "r"); if (fp == NULL) exit (1); + pkey = (EVP_PKEY*)PEM_ASN1_read ((char *(*)())d2i_PublicKey, + PEM_STRING_X509, + fp, + NULL, NULL); + if (pkey == NULL) { ERR_print_errors_fp (stderr); exit (1); } + fclose (fp); + + /* Verify the signature */ + + EVP_VerifyInit (&md_ctx, EVP_md5()); + EVP_VerifyUpdate (&md_ctx, data, strlen((char*)data)); + err = EVP_VerifyFinal (&md_ctx, + sig_buf, + sig_len, + pkey); + if (err != 1) { ERR_print_errors_fp (stderr); exit (1); } + EVP_PKEY_free (pkey); + printf ("Signature Verified Ok.\n"); +} +/* EOF */ +--------------- plain-cert.pem ----------------- +-----BEGIN CERTIFICATE----- +MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD +VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv +bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy +dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X +DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw +EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l +dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT +EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp +MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw +L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN +BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX +9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4= +-----END CERTIFICATE----- +---------------- plain-key.pem ----------------- +-----BEGIN RSA PRIVATE KEY----- +MIIBPAIBAAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNwL4lYKbpzzlmC5beaQXeQ +2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAAQJBALjkK+jc2+iihI98riEF +oudmkNziSRTYjnwjx8mCoAjPWviB3c742eO3FG4/soi1jD9A5alihEOXfUzloenr +8IECIQD3B5+0l+68BA/6d76iUNqAAV8djGTzvxnCxycnxPQydQIhAMXt4trUI3nc +a+U8YL2HPFA3gmhBsSICbq2OptOCnM7hAiEA6Xi3JIQECob8YwkRj29DU3/4WYD7 +WLPgsQpwo1GuSpECICGsnWH5oaeD9t9jbFoSfhJvv0IZmxdcLpRcpslpeWBBAiEA +6/5B8J0GHdJq89FHwEG/H2eVVUYu5y/aD6sgcm+0Avg= +-----END RSA PRIVATE KEY----- +------------------------------------------------ + diff --git a/demos/sign/sign.c b/demos/sign/sign.c new file mode 100644 index 0000000..a6c66e1 --- /dev/null +++ b/demos/sign/sign.c @@ -0,0 +1,153 @@ +/* demos/sign/sign.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* sign-it.cpp - Simple test app using SSLeay envelopes to sign data + 29.9.1996, Sampo Kellomaki */ + +/* converted to C - eay :-) */ + +/* reformated a bit and converted to use the more common functions: this was + * initially written at the dawn of time :-) - Steve. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int main () +{ + int err; + int sig_len; + unsigned char sig_buf [4096]; + static char certfile[] = "cert.pem"; + static char keyfile[] = "key.pem"; + static char data[] = "I owe you..."; + EVP_MD_CTX md_ctx; + EVP_PKEY * pkey; + FILE * fp; + X509 * x509; + + /* Just load the crypto library error strings, + * SSL_load_error_strings() loads the crypto AND the SSL ones */ + /* SSL_load_error_strings();*/ + ERR_load_crypto_strings(); + + /* Read private key */ + + fp = fopen (keyfile, "r"); + if (fp == NULL) exit (1); + pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); + fclose (fp); + + if (pkey == NULL) { + ERR_print_errors_fp (stderr); + exit (1); + } + + /* Do the signature */ + + EVP_SignInit (&md_ctx, EVP_sha1()); + EVP_SignUpdate (&md_ctx, data, strlen(data)); + sig_len = sizeof(sig_buf); + err = EVP_SignFinal (&md_ctx, sig_buf, &sig_len, pkey); + + if (err != 1) { + ERR_print_errors_fp(stderr); + exit (1); + } + + EVP_PKEY_free (pkey); + + /* Read public key */ + + fp = fopen (certfile, "r"); + if (fp == NULL) exit (1); + x509 = PEM_read_X509(fp, NULL, NULL, NULL); + fclose (fp); + + if (x509 == NULL) { + ERR_print_errors_fp (stderr); + exit (1); + } + + /* Get public key - eay */ + pkey=X509_get_pubkey(x509); + if (pkey == NULL) { + ERR_print_errors_fp (stderr); + exit (1); + } + + /* Verify the signature */ + + EVP_VerifyInit (&md_ctx, EVP_sha1()); + EVP_VerifyUpdate (&md_ctx, data, strlen((char*)data)); + err = EVP_VerifyFinal (&md_ctx, sig_buf, sig_len, pkey); + EVP_PKEY_free (pkey); + + if (err != 1) { + ERR_print_errors_fp (stderr); + exit (1); + } + printf ("Signature Verified Ok.\n"); + return(0); +} diff --git a/demos/sign/sign.txt b/demos/sign/sign.txt new file mode 100644 index 0000000..2aa2b46 --- /dev/null +++ b/demos/sign/sign.txt @@ -0,0 +1,170 @@ +From ssl-lists-owner@mincom.com Mon Sep 30 22:43:15 1996 +Received: from cygnus.mincom.oz.au by orb.mincom.oz.au with SMTP id AA12802 + (5.65c/IDA-1.4.4 for eay); Mon, 30 Sep 1996 12:45:43 +1000 +Received: (from daemon@localhost) by cygnus.mincom.oz.au (8.7.5/8.7.3) id MAA25922 for ssl-users-outgoing; Mon, 30 Sep 1996 12:43:43 +1000 (EST) +Received: from orb.mincom.oz.au (eay@orb.mincom.oz.au [192.55.197.1]) by cygnus.mincom.oz.au (8.7.5/8.7.3) with SMTP id MAA25900 for ; Mon, 30 Sep 1996 12:43:39 +1000 (EST) +Received: by orb.mincom.oz.au id AA12688 + (5.65c/IDA-1.4.4 for ssl-users@listserv.mincom.oz.au); Mon, 30 Sep 1996 12:43:16 +1000 +Date: Mon, 30 Sep 1996 12:43:15 +1000 (EST) +From: Eric Young +X-Sender: eay@orb +To: Sampo Kellomaki +Cc: ssl-users@mincom.com, sampo@brutus.neuronio.pt +Subject: Re: Signing with envelope routines +In-Reply-To: <199609300037.BAA08729@brutus.neuronio.pt> +Message-Id: +Mime-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +Sender: ssl-lists-owner@mincom.com +Precedence: bulk +Status: O +X-Status: + + +On Mon, 30 Sep 1996, Sampo Kellomaki wrote: +> I have been trying to figure out how to produce signatures with EVP_ +> routines. I seem to be able to read in private key and sign some +> data ok, but I can't figure out how I am supposed to read in +> public key so that I could verify my signature. I use self signed +> certificate. + +hmm... a rather poorly documented are of the library at this point in time. + +> I figured I should use +> EVP_PKEY* pkey = PEM_ASN1_read(d2i_PrivateKey, PEM_STRING_EVP_PKEY, +> fp, NULL, NULL); +> to read in private key and this seems to work Ok. +> +> However when I try analogous +> EVP_PKEY* pkey = PEM_ASN1_read(d2i_PublicKey, PEM_STRING_X509, +> fp, NULL, NULL); + +What you should do is + X509 *x509=PEM_read_X509(fp,NULL,NULL); + /* which is the same as PEM_ASN1_read(d2i_X509,PEM_STRING_X509,fp, + * NULL,NULL); */ +Then + EVP_PKEY *pkey=X509_extract_key(x509); + +There is also a X509_REQ_extract_key(req); +which gets the public key from a certificate request. + +I re-worked quite a bit of this when I cleaned up the dependancy on +RSA as the private key. + +> I figured that the second argument to PEM_ASN1_read should match the +> name in my PEM encoded object, hence PEM_STRING_X509. +> PEM_STRING_EVP_PKEY seems to be somehow magical +> because it matches whatever private key there happens to be. I could +> not find a similar constant to use with getting the certificate, however. + +:-), PEM_STRING_EVP_PKEY is 'magical' :-). In theory I should be using a +standard such as PKCS#8 to store the private key so that the type is +encoded in the asn.1 encoding of the object. + +> Is my approach of using PEM_ASN1_read correct? What should I pass in +> as name? Can I use normal (or even self signed) X509 certificate for +> verifying the signature? + +The actual public key is kept in the certificate, so basically you have +to load the certificate and then 'unpack' the public key from the +certificate. + +> When will SSLeay documentation be written ;-)? If I would contribute +> comments to the code, would Eric take time to review them and include +> them in distribution? + +:-) After SSLv3 and PKCS#7 :-). I actually started doing a function list +but what I really need to do is do quite a few 'this is how you do xyz' +type documents. I suppose the current method is to post to ssl-users and +I'll respond :-). + +I'll add a 'demo' directory for the next release, I've appended a +modified version of your program that works, you were very close :-). + +eric + +/* sign-it.cpp - Simple test app using SSLeay envelopes to sign data + 29.9.1996, Sampo Kellomaki */ + +/* converted to C - eay :-) */ + +#include +#include "rsa.h" +#include "evp.h" +#include "objects.h" +#include "x509.h" +#include "err.h" +#include "pem.h" +#include "ssl.h" + +void main () +{ + int err; + int sig_len; + unsigned char sig_buf [4096]; + static char certfile[] = "plain-cert.pem"; + static char keyfile[] = "plain-key.pem"; + static char data[] = "I owe you..."; + EVP_MD_CTX md_ctx; + EVP_PKEY * pkey; + FILE * fp; + X509 * x509; + + /* Just load the crypto library error strings, + * SSL_load_error_strings() loads the crypto AND the SSL ones */ + /* SSL_load_error_strings();*/ + ERR_load_crypto_strings(); + + /* Read private key */ + + fp = fopen (keyfile, "r"); if (fp == NULL) exit (1); + pkey = (EVP_PKEY*)PEM_ASN1_read ((char *(*)())d2i_PrivateKey, + PEM_STRING_EVP_PKEY, + fp, + NULL, NULL); + if (pkey == NULL) { ERR_print_errors_fp (stderr); exit (1); } + fclose (fp); + + /* Do the signature */ + + EVP_SignInit (&md_ctx, EVP_md5()); + EVP_SignUpdate (&md_ctx, data, strlen(data)); + sig_len = sizeof(sig_buf); + err = EVP_SignFinal (&md_ctx, + sig_buf, + &sig_len, + pkey); + if (err != 1) { ERR_print_errors_fp (stderr); exit (1); } + EVP_PKEY_free (pkey); + + /* Read public key */ + + fp = fopen (certfile, "r"); if (fp == NULL) exit (1); + x509 = (X509 *)PEM_ASN1_read ((char *(*)())d2i_X509, + PEM_STRING_X509, + fp, NULL, NULL); + if (x509 == NULL) { ERR_print_errors_fp (stderr); exit (1); } + fclose (fp); + + /* Get public key - eay */ + pkey=X509_extract_key(x509); + if (pkey == NULL) { ERR_print_errors_fp (stderr); exit (1); } + + /* Verify the signature */ + + EVP_VerifyInit (&md_ctx, EVP_md5()); + EVP_VerifyUpdate (&md_ctx, data, strlen((char*)data)); + err = EVP_VerifyFinal (&md_ctx, + sig_buf, + sig_len, + pkey); + if (err != 1) { ERR_print_errors_fp (stderr); exit (1); } + EVP_PKEY_free (pkey); + printf ("Signature Verified Ok.\n"); +} + + + + + diff --git a/demos/smime/cacert.pem b/demos/smime/cacert.pem new file mode 100644 index 0000000..75cbb34 --- /dev/null +++ b/demos/smime/cacert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6DCCAlGgAwIBAgIJAMfGO3rdo2uUMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV +BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv +dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTc0MzE3 +WhcNMTcwNDEwMTc0MzE3WjBXMQswCQYDVQQGEwJVSzESMBAGA1UEBxMJVGVzdCBD +aXR5MRYwFAYDVQQKEw1PcGVuU1NMIEdyb3VwMRwwGgYDVQQDExNUZXN0IFMvTUlN +RSBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqJMal1uC1/1wz +i5+dE4EZF2im3BgROm5PVMbwPY9V1t+KYvtdc3rMcRgJaMbP+qaEcDXoIsZfYXGR +ielgfDNZmZcj1y/FOum+Jc2OZMs3ggPmjIQ3dbBECq0hZKcbz7wfr+2OeNWm46iT +jcSIXpGIRhUYEzOgv7zb8oOU70IbbwIDAQABo4G7MIG4MB0GA1UdDgQWBBRHUypx +CXFQYqewhGo72lWPQUsjoDCBiAYDVR0jBIGAMH6AFEdTKnEJcVBip7CEajvaVY9B +SyOgoVukWTBXMQswCQYDVQQGEwJVSzESMBAGA1UEBxMJVGVzdCBDaXR5MRYwFAYD +VQQKEw1PcGVuU1NMIEdyb3VwMRwwGgYDVQQDExNUZXN0IFMvTUlNRSBSb290IENB +ggkAx8Y7et2ja5QwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQANI+Yc +G/YDM1WMUGEzEkU9UhsIUqdyBebnK3+OyxZSouDcE/M10jFJzBf/F5b0uUGAKWwo +u0dzmILfKjdfWe8EyCRafZcm00rVcO09i/63FBYzlHbmfUATIqZdhKzxxQMPs5mF +1je+pHUpzIY8TSXyh/uD9IkAy04IHwGZQf9akw== +-----END CERTIFICATE----- diff --git a/demos/smime/cakey.pem b/demos/smime/cakey.pem new file mode 100644 index 0000000..3b53c5e --- /dev/null +++ b/demos/smime/cakey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQCqJMal1uC1/1wzi5+dE4EZF2im3BgROm5PVMbwPY9V1t+KYvtd +c3rMcRgJaMbP+qaEcDXoIsZfYXGRielgfDNZmZcj1y/FOum+Jc2OZMs3ggPmjIQ3 +dbBECq0hZKcbz7wfr+2OeNWm46iTjcSIXpGIRhUYEzOgv7zb8oOU70IbbwIDAQAB +AoGBAKWOZ2UTc1BkjDjz0XoscmAR8Rj77MdGzfOPkIxPultSW+3yZpkGNyUbnsH5 +HAtf4Avai/m3bMN+s91kDpx9/g/I9ZEHPQLcDICETvwt/EHT7+hwvaQgsM+TgpMs +tjlGZOWent6wVIuvwwzqOMXZLgK9FvY7upwgtrys4G3Kab5hAkEA2QzFflWyEvKS +rMSaVtn/IjFilwa7H0IdakkjM34z4peerFTPBr4J47YD4RCR/dAvxyNy3zUxtH18 +9R6dUixI6QJBAMitJD0xOkbGWBX8KVJvRiKOIdf/95ZUAgN/h3bWKy57EB9NYj3u +jbxXcvdjfSqiITykkjAg7SG7nrlzJsu6CpcCQG6gVsy0auXDY0TRlASuaZ6I40Is +uRUOgqWYj2uAaHuWYdZeB4LdO3cnX0TISFDAWom6JKNlnmbrCtR4fSDT13kCQQCU ++VQJyV3F5MDHsWbLt6eNR46AV5lpk/vatPXPlrZ/zwPs+PmRmGLICvNiDA2DdNDP +wCx2Zjsj67CtY3rNitMJAkEAm09BQnjnbBXUb1rd2SjNDWTsu80Z+zLu8pAwXNhW +8nsvMYqlYMIxuMPwu/QuTnMRhMZ08uhqoD3ukZnBeoMEVg== +-----END RSA PRIVATE KEY----- diff --git a/demos/smime/encr.txt b/demos/smime/encr.txt new file mode 100644 index 0000000..f163a32 --- /dev/null +++ b/demos/smime/encr.txt @@ -0,0 +1,3 @@ +Content-type: text/plain + +Sample OpenSSL Data for PKCS#7 encryption diff --git a/demos/smime/sign.txt b/demos/smime/sign.txt new file mode 100644 index 0000000..af1341d --- /dev/null +++ b/demos/smime/sign.txt @@ -0,0 +1,3 @@ +Content-type: text/plain + +Test OpenSSL Signed Content diff --git a/demos/smime/signer.pem b/demos/smime/signer.pem new file mode 100644 index 0000000..bac16ba --- /dev/null +++ b/demos/smime/signer.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIICpjCCAg+gAwIBAgIJAJ+rfmEoLQRhMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV +BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv +dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTgyOTI3 +WhcNMTcwNDA5MTgyOTI3WjBWMQswCQYDVQQGEwJVSzElMCMGA1UEAxMcT3BlblNT +TCB0ZXN0IFMvTUlNRSBzaWduZXIgMTEgMB4GCSqGSIb3DQEJARYRdGVzdDFAb3Bl +bnNzbC5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL1ocAQ7ON2pIUXz +jwKPzpPB9ozB6PFG6F6kARO+i0DiT6Qn8abUjwpHPU+lGys83QlpbkQVUD6Fv/4L +ytihk6N9Pr/feECVcSZ20dI43WXjfYak14dSVrZkGNMMXqKmnnqtkAdD0oJN7A7y +gcf8RuViV0kvk9/36eCMwMHrImfhAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI +AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW +BBSyKqjvctIsFNBHULBTqr8SHtSxpDAfBgNVHSMEGDAWgBRHUypxCXFQYqewhGo7 +2lWPQUsjoDANBgkqhkiG9w0BAQQFAAOBgQBvdYVoBfd4RV/xWSMXIcgw/i5OiwyX +MsenQePll51MpglfArd7pUipUalCqlJt/Gs8kD16Ih1z1yuWYVTMlnDZ0PwbIOYn ++Jr8XLF9b1SMJt6PwckZZ0LZdIi2KwGAxVsIW1kjJAqu9o4YH37XW37yYdQRxfvv +lDiQlgX0JtmLgA== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC9aHAEOzjdqSFF848Cj86TwfaMwejxRuhepAETvotA4k+kJ/Gm +1I8KRz1PpRsrPN0JaW5EFVA+hb/+C8rYoZOjfT6/33hAlXEmdtHSON1l432GpNeH +Ula2ZBjTDF6ipp56rZAHQ9KCTewO8oHH/EblYldJL5Pf9+ngjMDB6yJn4QIDAQAB +AoGACCuYIWaYll80UzslYRvo8lC8nOfEb5v6bBKxBTQD98GLY+5hKywiG3RlPalG +mb/fXQeSPReaRYgpdwD1OBEIOEMW9kLyqpzokC0xjpZ+MwsuJTlxCesk5GEsMa3o +wC3QMmiRA7qrZ/SzTtwrs++9mZ/pxp8JZ6pKYUj8SE7/vV0CQQDz8Ix2t40E16hx +04+XhClnGqydZJyLLSxcTU3ZVhYxL+efo/5hZ8tKpkcDi8wq6T03BOKrKxrlIW55 +qDRNM24rAkEAxsWzu/rJhIouQyNoYygEIEYzFRlTQyZSg59u6dNiewMn27dOAbyc +YT7B6da7e74QttTXo0lIllsX2S38+XsIIwJBANSRuIU3G66tkr5l4gnhhAaxqtuY +sgVhvvdL8dvC9aG1Ifzt9hzBSthpHxbK+oYmK07HdhI8hLpIMLHYzoK7n3MCQEy4 +4rccBcxyyYiAkjozp+QNNIpgTBMPJ6pGT7lRLiHtBeV4y1NASdv/LTnk+Fi69Bid +7t3H24ytfHcHmS1yn6ECQF6Jmh4C7dlvp59zXp+t+VsXxa/8sq41vKNIj0Rx9vh5 +xp9XL0C5ZpgmBnsTydP9pmkiL4ltLbMX0wJU6N2cmFw= +-----END RSA PRIVATE KEY----- diff --git a/demos/smime/signer2.pem b/demos/smime/signer2.pem new file mode 100644 index 0000000..25e23d1 --- /dev/null +++ b/demos/smime/signer2.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIICpjCCAg+gAwIBAgIJAJ+rfmEoLQRiMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV +BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv +dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTgyOTQ0 +WhcNMTcwNDA5MTgyOTQ0WjBWMQswCQYDVQQGEwJVSzElMCMGA1UEAxMcT3BlblNT +TCB0ZXN0IFMvTUlNRSBzaWduZXIgMjEgMB4GCSqGSIb3DQEJARYRdGVzdDJAb3Bl +bnNzbC5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANco7VPgX9vcGwmZ +jYqjq1JiR7M38dsMNhuJyLRVjJ5/cpFluQydQuG1PhzOJ8zfYVFicOXKvbYuKuXW +ozZIwzqEqWsNf36KHTLS6yOMG8I13cRInh+fAIKq9Z8Eh65I7FJzVsNsfEQrGfEW +GMA8us24IaSvP3QkbfHJn/4RaKznAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI +AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW +BBRlrLQJUB8uAa4q8B2OqvvTXonF5zAfBgNVHSMEGDAWgBRHUypxCXFQYqewhGo7 +2lWPQUsjoDANBgkqhkiG9w0BAQQFAAOBgQBQbi2juGALg2k9m1hKpzR2lCGmGO3X +h3Jh/l0vIxDr0RTgP2vBrtITlx655P/o1snoeTIpYG8uUnFnTE/6YakdayAIlxV4 +aZl63AivZMpQB5SPaPH/jEsGJ8UQMfdiy4ORWIULupuPKlKwODNw7tVhQIACS/DR +2aX6rl2JEuJ5Yg== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDXKO1T4F/b3BsJmY2Ko6tSYkezN/HbDDYbici0VYyef3KRZbkM +nULhtT4czifM32FRYnDlyr22Lirl1qM2SMM6hKlrDX9+ih0y0usjjBvCNd3ESJ4f +nwCCqvWfBIeuSOxSc1bDbHxEKxnxFhjAPLrNuCGkrz90JG3xyZ/+EWis5wIDAQAB +AoGAUTB2bcIrKfGimjrBOGGOUmYXnD8uGnQ/LqENhU8K4vxApTD3ZRUqmbUknQYF +6r8YH/e/llasw8QkF9qod+F5GTgsnyh/aMidFHKrXXbf1662scz9+S6crSXq9Eb2 +CL57f6Kw61k6edrz8zHdA+rnTK00hzgzKCP4ZL5k8/55ueECQQD+BK+nsKi6CcKf +m3Mh61Sf2Icm5JlMCKaihlbnh78lBN1imYUAfHJEnQ1ujxXB94R+6o9S+XrWTnTX +2m/JNIfpAkEA2NaidX7Sv5jnRPkwJ02Srl0urxINLmg4bU0zmM3VoMklYBHWnMyr +upPZGPh5TzCa+g6FTBmU8XK61wvnEKNcTwJBAM24VdnlBIDGbsx8RJ3vzLU30xz4 +ff5J80okqjUQhwkgC3tTAZgHMTPITZyAXQqdvrxakoCMc6MkHxTBX08AMCECQHHL +SdyxXrYv7waSY0PtANJCkpJLveEhzqMFxdMmCjtj9BpTojYNbv3uQxtIopj9YAdk +gW2ray++zvC2DV/86x8CQH4UJwgO6JqU4bSgi6HiRNjDg26tJ0Beu8jjl1vrkIVX +pHFwSUeLZUsT2/iTUSgYH4uYiZPgYNcKTCT9W6se30A= +-----END RSA PRIVATE KEY----- diff --git a/demos/smime/smdec.c b/demos/smime/smdec.c new file mode 100644 index 0000000..8b1a854 --- /dev/null +++ b/demos/smime/smdec.c @@ -0,0 +1,83 @@ +/* Simple S/MIME signing example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL; + X509 *rcert = NULL; + EVP_PKEY *rkey = NULL; + PKCS7 *p7 = NULL; + int ret = 1; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Read in recipient certificate and private key */ + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + BIO_reset(tbio); + + rkey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); + + if (!rcert || !rkey) + goto err; + + /* Open content being signed */ + + in = BIO_new_file("smencr.txt", "r"); + + if (!in) + goto err; + + /* Sign content */ + p7 = SMIME_read_PKCS7(in, NULL); + + if (!p7) + goto err; + + out = BIO_new_file("encrout.txt", "w"); + if (!out) + goto err; + + /* Decrypt S/MIME message */ + if (!PKCS7_decrypt(p7, rkey, rcert, out, 0)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Signing Data\n"); + ERR_print_errors_fp(stderr); + } + + if (p7) + PKCS7_free(p7); + if (rcert) + X509_free(rcert); + if (rkey) + EVP_PKEY_free(rkey); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } + + + + diff --git a/demos/smime/smenc.c b/demos/smime/smenc.c new file mode 100644 index 0000000..77dd732 --- /dev/null +++ b/demos/smime/smenc.c @@ -0,0 +1,92 @@ +/* Simple S/MIME encrypt example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL; + X509 *rcert = NULL; + STACK_OF(X509) *recips = NULL; + PKCS7 *p7 = NULL; + int ret = 1; + + /* + * On OpenSSL 0.9.9 only: + * for streaming set PKCS7_STREAM + */ + int flags = PKCS7_STREAM; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Read in recipient certificate */ + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + if (!rcert) + goto err; + + /* Create recipient STACK and add recipient cert to it */ + recips = sk_X509_new_null(); + + if (!recips || !sk_X509_push(recips, rcert)) + goto err; + + /* sk_X509_pop_free will free up recipient STACK and its contents + * so set rcert to NULL so it isn't freed up twice. + */ + rcert = NULL; + + /* Open content being encrypted */ + + in = BIO_new_file("encr.txt", "r"); + + if (!in) + goto err; + + /* encrypt content */ + p7 = PKCS7_encrypt(recips, in, EVP_des_ede3_cbc(), flags); + + if (!p7) + goto err; + + out = BIO_new_file("smencr.txt", "w"); + if (!out) + goto err; + + /* Write out S/MIME message */ + if (!SMIME_write_PKCS7(out, p7, in, flags)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Encrypting Data\n"); + ERR_print_errors_fp(stderr); + } + + if (p7) + PKCS7_free(p7); + if (rcert) + X509_free(rcert); + if (recips) + sk_X509_pop_free(recips, X509_free); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } diff --git a/demos/smime/smsign.c b/demos/smime/smsign.c new file mode 100644 index 0000000..ba78830 --- /dev/null +++ b/demos/smime/smsign.c @@ -0,0 +1,89 @@ +/* Simple S/MIME signing example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL; + X509 *scert = NULL; + EVP_PKEY *skey = NULL; + PKCS7 *p7 = NULL; + int ret = 1; + + /* For simple S/MIME signing use PKCS7_DETACHED. + * On OpenSSL 0.9.9 only: + * for streaming detached set PKCS7_DETACHED|PKCS7_STREAM + * for streaming non-detached set PKCS7_STREAM + */ + int flags = PKCS7_DETACHED|PKCS7_STREAM; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Read in signer certificate and private key */ + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + scert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + BIO_reset(tbio); + + skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); + + if (!scert || !skey) + goto err; + + /* Open content being signed */ + + in = BIO_new_file("sign.txt", "r"); + + if (!in) + goto err; + + /* Sign content */ + p7 = PKCS7_sign(scert, skey, NULL, in, flags); + + if (!p7) + goto err; + + out = BIO_new_file("smout.txt", "w"); + if (!out) + goto err; + + if (!(flags & PKCS7_STREAM)) + BIO_reset(in); + + /* Write out S/MIME message */ + if (!SMIME_write_PKCS7(out, p7, in, flags)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Signing Data\n"); + ERR_print_errors_fp(stderr); + } + + if (p7) + PKCS7_free(p7); + if (scert) + X509_free(scert); + if (skey) + EVP_PKEY_free(skey); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } diff --git a/demos/smime/smsign2.c b/demos/smime/smsign2.c new file mode 100644 index 0000000..ff835c5 --- /dev/null +++ b/demos/smime/smsign2.c @@ -0,0 +1,107 @@ +/* S/MIME signing example: 2 signers. OpenSSL 0.9.9 only */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL; + X509 *scert = NULL, *scert2 = NULL; + EVP_PKEY *skey = NULL, *skey2 = NULL; + PKCS7 *p7 = NULL; + int ret = 1; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + tbio = BIO_new_file("signer.pem", "r"); + + if (!tbio) + goto err; + + scert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + BIO_reset(tbio); + + skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); + + BIO_free(tbio); + + tbio = BIO_new_file("signer2.pem", "r"); + + if (!tbio) + goto err; + + scert2 = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + BIO_reset(tbio); + + skey2 = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); + + if (!scert2 || !skey2) + goto err; + + in = BIO_new_file("sign.txt", "r"); + + if (!in) + goto err; + + p7 = PKCS7_sign(NULL, NULL, NULL, in, PKCS7_STREAM|PKCS7_PARTIAL); + + if (!p7) + goto err; + + /* Add each signer in turn */ + + if (!PKCS7_sign_add_signer(p7, scert, skey, NULL, 0)) + goto err; + + if (!PKCS7_sign_add_signer(p7, scert2, skey2, NULL, 0)) + goto err; + + out = BIO_new_file("smout.txt", "w"); + if (!out) + goto err; + + /* NB: content included and finalized by SMIME_write_PKCS7 */ + + if (!SMIME_write_PKCS7(out, p7, in, PKCS7_STREAM)) + goto err; + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Signing Data\n"); + ERR_print_errors_fp(stderr); + } + + if (p7) + PKCS7_free(p7); + + if (scert) + X509_free(scert); + if (skey) + EVP_PKEY_free(skey); + + if (scert2) + X509_free(scert2); + if (skey) + EVP_PKEY_free(skey2); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } + + + + diff --git a/demos/smime/smver.c b/demos/smime/smver.c new file mode 100644 index 0000000..9d360c2 --- /dev/null +++ b/demos/smime/smver.c @@ -0,0 +1,87 @@ +/* Simple S/MIME verification example */ +#include +#include +#include + +int main(int argc, char **argv) + { + BIO *in = NULL, *out = NULL, *tbio = NULL, *cont = NULL; + X509_STORE *st = NULL; + X509 *cacert = NULL; + PKCS7 *p7 = NULL; + + int ret = 1; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Set up trusted CA certificate store */ + + st = X509_STORE_new(); + + /* Read in signer certificate and private key */ + tbio = BIO_new_file("cacert.pem", "r"); + + if (!tbio) + goto err; + + cacert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + if (!cacert) + goto err; + + if (!X509_STORE_add_cert(st, cacert)) + goto err; + + /* Open content being signed */ + + in = BIO_new_file("smout.txt", "r"); + + if (!in) + goto err; + + /* Sign content */ + p7 = SMIME_read_PKCS7(in, &cont); + + if (!p7) + goto err; + + /* File to output verified content to */ + out = BIO_new_file("smver.txt", "w"); + if (!out) + goto err; + + if (!PKCS7_verify(p7, NULL, st, cont, out, 0)) + { + fprintf(stderr, "Verification Failure\n"); + goto err; + } + + fprintf(stderr, "Verification Successful\n"); + + ret = 0; + + err: + + if (ret) + { + fprintf(stderr, "Error Verifying Data\n"); + ERR_print_errors_fp(stderr); + } + + if (p7) + PKCS7_free(p7); + + if (cacert) + X509_free(cacert); + + if (in) + BIO_free(in); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; + + } diff --git a/demos/spkigen.c b/demos/spkigen.c new file mode 100644 index 0000000..2cd5dfe --- /dev/null +++ b/demos/spkigen.c @@ -0,0 +1,161 @@ +/* NOCW */ +/* demos/spkigen.c + * 18-Mar-1997 - eay - A quick hack :-) + * version 1.1, it would probably help to save or load the + * private key :-) + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* The following two don't exist in SSLeay but they are in here as + * examples */ +#define PEM_write_SPKI(fp,x) \ + PEM_ASN1_write((int (*)())i2d_NETSCAPE_SPKI,"SPKI",fp,\ + (char *)x,NULL,NULL,0,NULL) +int SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey); + +/* These are defined in the next version of SSLeay */ +int EVP_PKEY_assign(EVP_PKEY *pkey, int type,char *key); +#define RSA_F4 0x10001 +#define EVP_PKEY_assign_RSA(pkey,rsa) EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\ + (char *)(rsa)) + +int main(argc,argv) +int argc; +char *argv[]; + { + RSA *rsa=NULL; + NETSCAPE_SPKI *spki=NULL; + EVP_PKEY *pkey=NULL; + char buf[128]; + int ok=0,i; + FILE *fp; + + pkey=EVP_PKEY_new(); + + if (argc < 2) + { + /* Generate an RSA key, the random state should have been seeded + * with lots of calls to RAND_seed(....) */ + fprintf(stderr,"generating RSA key, could take some time...\n"); + if ((rsa=RSA_generate_key(512,RSA_F4,NULL)) == NULL) goto err; + } + else + { + if ((fp=fopen(argv[1],"r")) == NULL) + { perror(argv[1]); goto err; } + if ((rsa=PEM_read_RSAPrivateKey(fp,NULL,NULL)) == NULL) + goto err; + fclose(fp); + } + + if (!EVP_PKEY_assign_RSA(pkey,rsa)) goto err; + rsa=NULL; + + /* lets make the spki and set the public key and challenge */ + if ((spki=NETSCAPE_SPKI_new()) == NULL) goto err; + + if (!SPKI_set_pubkey(spki,pkey)) goto err; + + fprintf(stderr,"please enter challenge string:"); + fflush(stderr); + buf[0]='\0'; + fgets(buf,sizeof buf,stdin); + i=strlen(buf); + if (i > 0) buf[--i]='\0'; + if (!ASN1_STRING_set((ASN1_STRING *)spki->spkac->challenge, + buf,i)) goto err; + + if (!NETSCAPE_SPKI_sign(spki,pkey,EVP_md5())) goto err; + PEM_write_SPKI(stdout,spki); + if (argc < 2) + PEM_write_RSAPrivateKey(stdout,pkey->pkey.rsa,NULL,NULL,0,NULL); + + ok=1; +err: + if (!ok) + { + fprintf(stderr,"something bad happened...."); + ERR_print_errors_fp(stderr); + } + NETSCAPE_SPKI_free(spki); + EVP_PKEY_free(pkey); + exit(!ok); + } + +/* This function is in the next version of SSLeay */ +int EVP_PKEY_assign(pkey,type,key) +EVP_PKEY *pkey; +int type; +char *key; + { + if (pkey == NULL) return(0); + if (pkey->pkey.ptr != NULL) + { + if (pkey->type == EVP_PKEY_RSA) + RSA_free(pkey->pkey.rsa); + /* else memory leak */ + } + pkey->type=type; + pkey->pkey.ptr=key; + return(1); + } + +/* While I have a + * X509_set_pubkey() and X509_REQ_set_pubkey(), SPKI_set_pubkey() does + * not currently exist so here is a version of it. + * The next SSLeay release will probably have + * X509_set_pubkey(), + * X509_REQ_set_pubkey() and + * NETSCAPE_SPKI_set_pubkey() + * as macros calling the same function */ +int SPKI_set_pubkey(x,pkey) +NETSCAPE_SPKI *x; +EVP_PKEY *pkey; + { + int ok=0; + X509_PUBKEY *pk; + X509_ALGOR *a; + ASN1_OBJECT *o; + unsigned char *s,*p; + int i; + + if (x == NULL) return(0); + + if ((pk=X509_PUBKEY_new()) == NULL) goto err; + a=pk->algor; + + /* set the algorithm id */ + if ((o=OBJ_nid2obj(pkey->type)) == NULL) goto err; + ASN1_OBJECT_free(a->algorithm); + a->algorithm=o; + + /* Set the parameter list */ + if ((a->parameter == NULL) || (a->parameter->type != V_ASN1_NULL)) + { + ASN1_TYPE_free(a->parameter); + a->parameter=ASN1_TYPE_new(); + a->parameter->type=V_ASN1_NULL; + } + i=i2d_PublicKey(pkey,NULL); + if ((s=(unsigned char *)malloc(i+1)) == NULL) goto err; + p=s; + i2d_PublicKey(pkey,&p); + if (!ASN1_BIT_STRING_set(pk->public_key,s,i)) goto err; + free(s); + + X509_PUBKEY_free(x->spkac->pubkey); + x->spkac->pubkey=pk; + pk=NULL; + ok=1; +err: + if (pk != NULL) X509_PUBKEY_free(pk); + return(ok); + } + diff --git a/demos/ssl/cli.cpp b/demos/ssl/cli.cpp new file mode 100644 index 0000000..49cba5d --- /dev/null +++ b/demos/ssl/cli.cpp @@ -0,0 +1,110 @@ +/* cli.cpp - Minimal ssleay client for Unix + 30.9.1996, Sampo Kellomaki */ + +/* mangled to work with SSLeay-0.9.0b and OpenSSL 0.9.2b + Simplified to be even more minimal + 12/98 - 4/99 Wade Scholine */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#define CHK_NULL(x) if ((x)==NULL) exit (1) +#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); } +#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); } + +void main () +{ + int err; + int sd; + struct sockaddr_in sa; + SSL_CTX* ctx; + SSL* ssl; + X509* server_cert; + char* str; + char buf [4096]; + SSL_METHOD *meth; + + SSLeay_add_ssl_algorithms(); + meth = SSLv2_client_method(); + SSL_load_error_strings(); + ctx = SSL_CTX_new (meth); CHK_NULL(ctx); + + CHK_SSL(err); + + /* ----------------------------------------------- */ + /* Create a socket and connect to server using normal socket calls. */ + + sd = socket (AF_INET, SOCK_STREAM, 0); CHK_ERR(sd, "socket"); + + memset (&sa, '\0', sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = inet_addr ("127.0.0.1"); /* Server IP */ + sa.sin_port = htons (1111); /* Server Port number */ + + err = connect(sd, (struct sockaddr*) &sa, + sizeof(sa)); CHK_ERR(err, "connect"); + + /* ----------------------------------------------- */ + /* Now we have TCP conncetion. Start SSL negotiation. */ + + ssl = SSL_new (ctx); CHK_NULL(ssl); + SSL_set_fd (ssl, sd); + err = SSL_connect (ssl); CHK_SSL(err); + + /* Following two steps are optional and not required for + data exchange to be successful. */ + + /* Get the cipher - opt */ + + printf ("SSL connection using %s\n", SSL_get_cipher (ssl)); + + /* Get server's certificate (note: beware of dynamic allocation) - opt */ + + server_cert = SSL_get_peer_certificate (ssl); CHK_NULL(server_cert); + printf ("Server certificate:\n"); + + str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0); + CHK_NULL(str); + printf ("\t subject: %s\n", str); + OPENSSL_free (str); + + str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0); + CHK_NULL(str); + printf ("\t issuer: %s\n", str); + OPENSSL_free (str); + + /* We could do all sorts of certificate verification stuff here before + deallocating the certificate. */ + + X509_free (server_cert); + + /* --------------------------------------------------- */ + /* DATA EXCHANGE - Send a message and receive a reply. */ + + err = SSL_write (ssl, "Hello World!", strlen("Hello World!")); CHK_SSL(err); + + err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err); + buf[err] = '\0'; + printf ("Got %d chars:'%s'\n", err, buf); + SSL_shutdown (ssl); /* send SSL/TLS close_notify */ + + /* Clean up. */ + + close (sd); + SSL_free (ssl); + SSL_CTX_free (ctx); +} +/* EOF - cli.cpp */ diff --git a/demos/ssl/inetdsrv.cpp b/demos/ssl/inetdsrv.cpp new file mode 100644 index 0000000..efd70d2 --- /dev/null +++ b/demos/ssl/inetdsrv.cpp @@ -0,0 +1,98 @@ +/* inetdserv.cpp - Minimal ssleay server for Unix inetd.conf + * 30.9.1996, Sampo Kellomaki + * From /etc/inetd.conf: + * 1111 stream tcp nowait sampo /usr/users/sampo/demo/inetdserv inetdserv + */ + +#include +#include + +#include "rsa.h" /* SSLeay stuff */ +#include +#include +#include +#include +#include + +#define HOME "/usr/users/sampo/demo/" +#define CERTF HOME "plain-cert.pem" +#define KEYF HOME "plain-key.pem" + +#define CHK_NULL(x) if ((x)==NULL) exit (1) +#define CHK_ERR(err,s) if ((err)==-1) \ + { fprintf(log, "%s %d\n", (s), errno); exit(1); } +#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(log); exit(2); } + +void main () +{ + int err; + SSL_CTX* ctx; + SSL* ssl; + X509* client_cert; + char* str; + char buf [4096]; + FILE* log; + + log = fopen ("/dev/console", "a"); CHK_NULL(log); + fprintf (log, "inetdserv %ld\n", (long)getpid()); + + SSL_load_error_strings(); + ctx = SSL_CTX_new (); CHK_NULL(ctx); + + err = SSL_CTX_use_RSAPrivateKey_file (ctx, KEYF, SSL_FILETYPE_PEM); + CHK_SSL (err); + + err = SSL_CTX_use_certificate_file (ctx, CERTF, SSL_FILETYPE_PEM); + CHK_SSL (err); + + /* inetd has already opened the TCP connection, so we can get right + down to business. */ + + ssl = SSL_new (ctx); CHK_NULL(ssl); + SSL_set_fd (ssl, fileno(stdin)); + err = SSL_accept (ssl); CHK_SSL(err); + + /* Get the cipher - opt */ + + fprintf (log, "SSL connection using %s\n", SSL_get_cipher (ssl)); + + /* Get client's certificate (note: beware of dynamic allocation) - opt */ + + client_cert = SSL_get_peer_certificate (ssl); + if (client_cert != NULL) { + fprintf (log, "Client certificate:\n"); + + str = X509_NAME_oneline (X509_get_subject_name (client_cert)); + CHK_NULL(str); + fprintf (log, "\t subject: %s\n", str); + OPENSSL_free (str); + + str = X509_NAME_oneline (X509_get_issuer_name (client_cert)); + CHK_NULL(str); + fprintf (log, "\t issuer: %s\n", str); + OPENSSL_free (str); + + /* We could do all sorts of certificate verification stuff here before + deallocating the certificate. */ + + X509_free (client_cert); + } else + fprintf (log, "Client doe not have certificate.\n"); + + /* ------------------------------------------------- */ + /* DATA EXCHANGE: Receive message and send reply */ + + err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err); + buf[err] = '\0'; + fprintf (log, "Got %d chars:'%s'\n", err, buf); + + err = SSL_write (ssl, "Loud and clear.", strlen("Loud and clear.")); + CHK_SSL(err); + + /* Clean up. */ + + fclose (log); + SSL_free (ssl); + SSL_CTX_free (ctx); +} +/* EOF - inetdserv.cpp */ diff --git a/demos/ssl/serv.cpp b/demos/ssl/serv.cpp new file mode 100644 index 0000000..b142c75 --- /dev/null +++ b/demos/ssl/serv.cpp @@ -0,0 +1,152 @@ +/* serv.cpp - Minimal ssleay server for Unix + 30.9.1996, Sampo Kellomaki */ + + +/* mangled to work with SSLeay-0.9.0b and OpenSSL 0.9.2b + Simplified to be even more minimal + 12/98 - 4/99 Wade Scholine */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* SSLeay stuff */ +#include +#include +#include +#include +#include + + +/* define HOME to be dir for key and cert files... */ +#define HOME "./" +/* Make these what you want for cert & key files */ +#define CERTF HOME "foo-cert.pem" +#define KEYF HOME "foo-cert.pem" + + +#define CHK_NULL(x) if ((x)==NULL) exit (1) +#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); } +#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); } + +void main () +{ + int err; + int listen_sd; + int sd; + struct sockaddr_in sa_serv; + struct sockaddr_in sa_cli; + size_t client_len; + SSL_CTX* ctx; + SSL* ssl; + X509* client_cert; + char* str; + char buf [4096]; + SSL_METHOD *meth; + + /* SSL preliminaries. We keep the certificate and key with the context. */ + + SSL_load_error_strings(); + SSLeay_add_ssl_algorithms(); + meth = SSLv23_server_method(); + ctx = SSL_CTX_new (meth); + if (!ctx) { + ERR_print_errors_fp(stderr); + exit(2); + } + + if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) { + ERR_print_errors_fp(stderr); + exit(3); + } + if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) { + ERR_print_errors_fp(stderr); + exit(4); + } + + if (!SSL_CTX_check_private_key(ctx)) { + fprintf(stderr,"Private key does not match the certificate public key\n"); + exit(5); + } + + /* ----------------------------------------------- */ + /* Prepare TCP socket for receiving connections */ + + listen_sd = socket (AF_INET, SOCK_STREAM, 0); CHK_ERR(listen_sd, "socket"); + + memset (&sa_serv, '\0', sizeof(sa_serv)); + sa_serv.sin_family = AF_INET; + sa_serv.sin_addr.s_addr = INADDR_ANY; + sa_serv.sin_port = htons (1111); /* Server Port number */ + + err = bind(listen_sd, (struct sockaddr*) &sa_serv, + sizeof (sa_serv)); CHK_ERR(err, "bind"); + + /* Receive a TCP connection. */ + + err = listen (listen_sd, 5); CHK_ERR(err, "listen"); + + client_len = sizeof(sa_cli); + sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len); + CHK_ERR(sd, "accept"); + close (listen_sd); + + printf ("Connection from %lx, port %x\n", + sa_cli.sin_addr.s_addr, sa_cli.sin_port); + + /* ----------------------------------------------- */ + /* TCP connection is ready. Do server side SSL. */ + + ssl = SSL_new (ctx); CHK_NULL(ssl); + SSL_set_fd (ssl, sd); + err = SSL_accept (ssl); CHK_SSL(err); + + /* Get the cipher - opt */ + + printf ("SSL connection using %s\n", SSL_get_cipher (ssl)); + + /* Get client's certificate (note: beware of dynamic allocation) - opt */ + + client_cert = SSL_get_peer_certificate (ssl); + if (client_cert != NULL) { + printf ("Client certificate:\n"); + + str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0); + CHK_NULL(str); + printf ("\t subject: %s\n", str); + OPENSSL_free (str); + + str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0); + CHK_NULL(str); + printf ("\t issuer: %s\n", str); + OPENSSL_free (str); + + /* We could do all sorts of certificate verification stuff here before + deallocating the certificate. */ + + X509_free (client_cert); + } else + printf ("Client does not have certificate.\n"); + + /* DATA EXCHANGE - Receive message and send reply. */ + + err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err); + buf[err] = '\0'; + printf ("Got %d chars:'%s'\n", err, buf); + + err = SSL_write (ssl, "I hear you.", strlen("I hear you.")); CHK_SSL(err); + + /* Clean up. */ + + close (sd); + SSL_free (ssl); + SSL_CTX_free (ctx); +} +/* EOF - serv.cpp */ diff --git a/demos/ssltest-ecc/ECC-RSAcertgen.sh b/demos/ssltest-ecc/ECC-RSAcertgen.sh new file mode 100755 index 0000000..b31a4f1 --- /dev/null +++ b/demos/ssltest-ecc/ECC-RSAcertgen.sh @@ -0,0 +1,98 @@ +#!/bin/sh + +# For a list of supported curves, use "apps/openssl ecparam -list_curves". + +# Path to the openssl distribution +OPENSSL_DIR=../.. +# Path to the openssl program +OPENSSL_CMD=$OPENSSL_DIR/apps/openssl +# Option to find configuration file +OPENSSL_CNF="-config $OPENSSL_DIR/apps/openssl.cnf" +# Directory where certificates are stored +CERTS_DIR=./Certs +# Directory where private key files are stored +KEYS_DIR=$CERTS_DIR +# Directory where combo files (containing a certificate and corresponding +# private key together) are stored +COMBO_DIR=$CERTS_DIR +# cat command +CAT=/bin/cat +# rm command +RM=/bin/rm +# mkdir command +MKDIR=/bin/mkdir +# The certificate will expire these many days after the issue date. +DAYS=1500 +TEST_CA_FILE=rsa1024TestCA + +TEST_SERVER_CURVE=sect163r1 +TEST_SERVER_FILE=sect163r1-rsaTestServer +TEST_SERVER_DN="/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Microsystems Laboratories/CN=Test Server (sect163r1 key signed with RSA)" + +TEST_CLIENT_CURVE=sect163r1 +TEST_CLIENT_FILE=sect163r1-rsaTestClient +TEST_CLIENT_DN="/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Microsystems Laboratories/CN=Test Client (sect163r1 key signed with RSA)" + +# Generating an EC certificate involves the following main steps +# 1. Generating curve parameters (if needed) +# 2. Generating a certificate request +# 3. Signing the certificate request +# 4. [Optional] One can combine the cert and private key into a single +# file and also delete the certificate request + +$MKDIR -p $CERTS_DIR +$MKDIR -p $KEYS_DIR +$MKDIR -p $COMBO_DIR + +echo "GENERATING A TEST SERVER CERTIFICATE (ECC key signed with RSA)" +echo "==============================================================" +$OPENSSL_CMD ecparam -name $TEST_SERVER_CURVE -out $TEST_SERVER_CURVE.pem + +$OPENSSL_CMD req $OPENSSL_CNF -nodes -subj "$TEST_SERVER_DN" \ + -keyout $KEYS_DIR/$TEST_SERVER_FILE.key.pem \ + -newkey ec:$TEST_SERVER_CURVE.pem -new \ + -out $CERTS_DIR/$TEST_SERVER_FILE.req.pem + +$OPENSSL_CMD x509 -req -days $DAYS \ + -in $CERTS_DIR/$TEST_SERVER_FILE.req.pem \ + -CA $CERTS_DIR/$TEST_CA_FILE.cert.pem \ + -CAkey $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -out $CERTS_DIR/$TEST_SERVER_FILE.cert.pem -CAcreateserial + +# Display the certificate +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_SERVER_FILE.cert.pem -text + +# Place the certificate and key in a common file +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_SERVER_FILE.cert.pem -issuer -subject \ + > $COMBO_DIR/$TEST_SERVER_FILE.pem +$CAT $KEYS_DIR/$TEST_SERVER_FILE.key.pem >> $COMBO_DIR/$TEST_SERVER_FILE.pem + +# Remove the cert request file (no longer needed) +$RM $CERTS_DIR/$TEST_SERVER_FILE.req.pem + +echo "GENERATING A TEST CLIENT CERTIFICATE (ECC key signed with RSA)" +echo "==============================================================" +$OPENSSL_CMD ecparam -name $TEST_CLIENT_CURVE -out $TEST_CLIENT_CURVE.pem + +$OPENSSL_CMD req $OPENSSL_CNF -nodes -subj "$TEST_CLIENT_DN" \ + -keyout $KEYS_DIR/$TEST_CLIENT_FILE.key.pem \ + -newkey ec:$TEST_CLIENT_CURVE.pem -new \ + -out $CERTS_DIR/$TEST_CLIENT_FILE.req.pem + +$OPENSSL_CMD x509 -req -days $DAYS \ + -in $CERTS_DIR/$TEST_CLIENT_FILE.req.pem \ + -CA $CERTS_DIR/$TEST_CA_FILE.cert.pem \ + -CAkey $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -out $CERTS_DIR/$TEST_CLIENT_FILE.cert.pem -CAcreateserial + +# Display the certificate +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CLIENT_FILE.cert.pem -text + +# Place the certificate and key in a common file +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CLIENT_FILE.cert.pem -issuer -subject \ + > $COMBO_DIR/$TEST_CLIENT_FILE.pem +$CAT $KEYS_DIR/$TEST_CLIENT_FILE.key.pem >> $COMBO_DIR/$TEST_CLIENT_FILE.pem + +# Remove the cert request file (no longer needed) +$RM $CERTS_DIR/$TEST_CLIENT_FILE.req.pem + diff --git a/demos/ssltest-ecc/ECCcertgen.sh b/demos/ssltest-ecc/ECCcertgen.sh new file mode 100755 index 0000000..a47b8bb --- /dev/null +++ b/demos/ssltest-ecc/ECCcertgen.sh @@ -0,0 +1,164 @@ +#!/bin/sh + +# For a list of supported curves, use "apps/openssl ecparam -list_curves". + +# Path to the openssl distribution +OPENSSL_DIR=../.. +# Path to the openssl program +OPENSSL_CMD=$OPENSSL_DIR/apps/openssl +# Option to find configuration file +OPENSSL_CNF="-config $OPENSSL_DIR/apps/openssl.cnf" +# Directory where certificates are stored +CERTS_DIR=./Certs +# Directory where private key files are stored +KEYS_DIR=$CERTS_DIR +# Directory where combo files (containing a certificate and corresponding +# private key together) are stored +COMBO_DIR=$CERTS_DIR +# cat command +CAT=/bin/cat +# rm command +RM=/bin/rm +# mkdir command +MKDIR=/bin/mkdir +# The certificate will expire these many days after the issue date. +DAYS=1500 +TEST_CA_CURVE=secp160r1 +TEST_CA_FILE=secp160r1TestCA +TEST_CA_DN="/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Microsystems Laboratories/CN=Test CA (Elliptic curve secp160r1)" + +TEST_SERVER_CURVE=secp160r2 +TEST_SERVER_FILE=secp160r2TestServer +TEST_SERVER_DN="/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Microsystems Laboratories/CN=Test Server (Elliptic curve secp160r2)" + +TEST_CLIENT_CURVE=secp160r2 +TEST_CLIENT_FILE=secp160r2TestClient +TEST_CLIENT_DN="/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Microsystems Laboratories/CN=Test Client (Elliptic curve secp160r2)" + +# Generating an EC certificate involves the following main steps +# 1. Generating curve parameters (if needed) +# 2. Generating a certificate request +# 3. Signing the certificate request +# 4. [Optional] One can combine the cert and private key into a single +# file and also delete the certificate request + +$MKDIR -p $CERTS_DIR +$MKDIR -p $KEYS_DIR +$MKDIR -p $COMBO_DIR + +echo "Generating self-signed CA certificate (on curve $TEST_CA_CURVE)" +echo "===============================================================" +$OPENSSL_CMD ecparam -name $TEST_CA_CURVE -out $TEST_CA_CURVE.pem + +# Generate a new certificate request in $TEST_CA_FILE.req.pem. A +# new ecdsa (actually ECC) key pair is generated on the parameters in +# $TEST_CA_CURVE.pem and the private key is saved in $TEST_CA_FILE.key.pem +# WARNING: By using the -nodes option, we force the private key to be +# stored in the clear (rather than encrypted with a password). +$OPENSSL_CMD req $OPENSSL_CNF -nodes -subj "$TEST_CA_DN" \ + -keyout $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -newkey ec:$TEST_CA_CURVE.pem -new \ + -out $CERTS_DIR/$TEST_CA_FILE.req.pem + +# Sign the certificate request in $TEST_CA_FILE.req.pem using the +# private key in $TEST_CA_FILE.key.pem and include the CA extension. +# Make the certificate valid for 1500 days from the time of signing. +# The certificate is written into $TEST_CA_FILE.cert.pem +$OPENSSL_CMD x509 -req -days $DAYS \ + -in $CERTS_DIR/$TEST_CA_FILE.req.pem \ + -extfile $OPENSSL_DIR/apps/openssl.cnf \ + -extensions v3_ca \ + -signkey $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -out $CERTS_DIR/$TEST_CA_FILE.cert.pem + +# Display the certificate +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CA_FILE.cert.pem -text + +# Place the certificate and key in a common file +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CA_FILE.cert.pem -issuer -subject \ + > $COMBO_DIR/$TEST_CA_FILE.pem +$CAT $KEYS_DIR/$TEST_CA_FILE.key.pem >> $COMBO_DIR/$TEST_CA_FILE.pem + +# Remove the cert request file (no longer needed) +$RM $CERTS_DIR/$TEST_CA_FILE.req.pem + +echo "GENERATING A TEST SERVER CERTIFICATE (on elliptic curve $TEST_SERVER_CURVE)" +echo "==========================================================================" +# Generate parameters for curve $TEST_SERVER_CURVE, if needed +$OPENSSL_CMD ecparam -name $TEST_SERVER_CURVE -out $TEST_SERVER_CURVE.pem + +# Generate a new certificate request in $TEST_SERVER_FILE.req.pem. A +# new ecdsa (actually ECC) key pair is generated on the parameters in +# $TEST_SERVER_CURVE.pem and the private key is saved in +# $TEST_SERVER_FILE.key.pem +# WARNING: By using the -nodes option, we force the private key to be +# stored in the clear (rather than encrypted with a password). +$OPENSSL_CMD req $OPENSSL_CNF -nodes -subj "$TEST_SERVER_DN" \ + -keyout $KEYS_DIR/$TEST_SERVER_FILE.key.pem \ + -newkey ec:$TEST_SERVER_CURVE.pem -new \ + -out $CERTS_DIR/$TEST_SERVER_FILE.req.pem + +# Sign the certificate request in $TEST_SERVER_FILE.req.pem using the +# CA certificate in $TEST_CA_FILE.cert.pem and the CA private key in +# $TEST_CA_FILE.key.pem. Since we do not have an existing serial number +# file for this CA, create one. Make the certificate valid for $DAYS days +# from the time of signing. The certificate is written into +# $TEST_SERVER_FILE.cert.pem +$OPENSSL_CMD x509 -req -days $DAYS \ + -in $CERTS_DIR/$TEST_SERVER_FILE.req.pem \ + -CA $CERTS_DIR/$TEST_CA_FILE.cert.pem \ + -CAkey $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -out $CERTS_DIR/$TEST_SERVER_FILE.cert.pem -CAcreateserial + +# Display the certificate +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_SERVER_FILE.cert.pem -text + +# Place the certificate and key in a common file +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_SERVER_FILE.cert.pem -issuer -subject \ + > $COMBO_DIR/$TEST_SERVER_FILE.pem +$CAT $KEYS_DIR/$TEST_SERVER_FILE.key.pem >> $COMBO_DIR/$TEST_SERVER_FILE.pem + +# Remove the cert request file (no longer needed) +$RM $CERTS_DIR/$TEST_SERVER_FILE.req.pem + +echo "GENERATING A TEST CLIENT CERTIFICATE (on elliptic curve $TEST_CLIENT_CURVE)" +echo "==========================================================================" +# Generate parameters for curve $TEST_CLIENT_CURVE, if needed +$OPENSSL_CMD ecparam -name $TEST_CLIENT_CURVE -out $TEST_CLIENT_CURVE.pem + +# Generate a new certificate request in $TEST_CLIENT_FILE.req.pem. A +# new ecdsa (actually ECC) key pair is generated on the parameters in +# $TEST_CLIENT_CURVE.pem and the private key is saved in +# $TEST_CLIENT_FILE.key.pem +# WARNING: By using the -nodes option, we force the private key to be +# stored in the clear (rather than encrypted with a password). +$OPENSSL_CMD req $OPENSSL_CNF -nodes -subj "$TEST_CLIENT_DN" \ + -keyout $KEYS_DIR/$TEST_CLIENT_FILE.key.pem \ + -newkey ec:$TEST_CLIENT_CURVE.pem -new \ + -out $CERTS_DIR/$TEST_CLIENT_FILE.req.pem + +# Sign the certificate request in $TEST_CLIENT_FILE.req.pem using the +# CA certificate in $TEST_CA_FILE.cert.pem and the CA private key in +# $TEST_CA_FILE.key.pem. Since we do not have an existing serial number +# file for this CA, create one. Make the certificate valid for $DAYS days +# from the time of signing. The certificate is written into +# $TEST_CLIENT_FILE.cert.pem +$OPENSSL_CMD x509 -req -days $DAYS \ + -in $CERTS_DIR/$TEST_CLIENT_FILE.req.pem \ + -CA $CERTS_DIR/$TEST_CA_FILE.cert.pem \ + -CAkey $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -out $CERTS_DIR/$TEST_CLIENT_FILE.cert.pem -CAcreateserial + +# Display the certificate +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CLIENT_FILE.cert.pem -text + +# Place the certificate and key in a common file +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CLIENT_FILE.cert.pem -issuer -subject \ + > $COMBO_DIR/$TEST_CLIENT_FILE.pem +$CAT $KEYS_DIR/$TEST_CLIENT_FILE.key.pem >> $COMBO_DIR/$TEST_CLIENT_FILE.pem + +# Remove the cert request file (no longer needed) +$RM $CERTS_DIR/$TEST_CLIENT_FILE.req.pem + + + diff --git a/demos/ssltest-ecc/README b/demos/ssltest-ecc/README new file mode 100644 index 0000000..71c070a --- /dev/null +++ b/demos/ssltest-ecc/README @@ -0,0 +1,15 @@ +Scripts for using ECC ciphersuites with test/testssl +(these ciphersuites are described in the Internet Draft available at +http://www.ietf.org/internet-drafts/draft-ietf-tls-ecc-03.txt). + +Use ECCcertgen.sh, RSAcertgen.sh, ECC-RSAcertgen.sh to generate +root, client and server certs of the following types: + + ECC certs signed with ECDSA + RSA certs signed with RSA + ECC certs signed with RSA + +Afterwards, you can use ssltest.sh to run the various tests; +specify one of the following options: + + aecdh, ecdh-ecdsa, ecdhe-ecdsa, ecdh-rsa, ecdhe-rsa diff --git a/demos/ssltest-ecc/RSAcertgen.sh b/demos/ssltest-ecc/RSAcertgen.sh new file mode 100755 index 0000000..0cb0153 --- /dev/null +++ b/demos/ssltest-ecc/RSAcertgen.sh @@ -0,0 +1,121 @@ +#!/bin/sh + +# For a list of supported curves, use "apps/openssl ecparam -list_curves". + +# Path to the openssl distribution +OPENSSL_DIR=../.. +# Path to the openssl program +OPENSSL_CMD=$OPENSSL_DIR/apps/openssl +# Option to find configuration file +OPENSSL_CNF="-config $OPENSSL_DIR/apps/openssl.cnf" +# Directory where certificates are stored +CERTS_DIR=./Certs +# Directory where private key files are stored +KEYS_DIR=$CERTS_DIR +# Directory where combo files (containing a certificate and corresponding +# private key together) are stored +COMBO_DIR=$CERTS_DIR +# cat command +CAT=/bin/cat +# rm command +RM=/bin/rm +# mkdir command +MKDIR=/bin/mkdir +# The certificate will expire these many days after the issue date. +DAYS=1500 +TEST_CA_FILE=rsa1024TestCA +TEST_CA_DN="/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Microsystems Laboratories/CN=Test CA (1024 bit RSA)" + +TEST_SERVER_FILE=rsa1024TestServer +TEST_SERVER_DN="/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Microsystems Laboratories/CN=Test Server (1024 bit RSA)" + +TEST_CLIENT_FILE=rsa1024TestClient +TEST_CLIENT_DN="/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Microsystems Laboratories/CN=Test Client (1024 bit RSA)" + +# Generating an EC certificate involves the following main steps +# 1. Generating curve parameters (if needed) +# 2. Generating a certificate request +# 3. Signing the certificate request +# 4. [Optional] One can combine the cert and private key into a single +# file and also delete the certificate request + +$MKDIR -p $CERTS_DIR +$MKDIR -p $KEYS_DIR +$MKDIR -p $COMBO_DIR + +echo "Generating self-signed CA certificate (RSA)" +echo "===========================================" + +$OPENSSL_CMD req $OPENSSL_CNF -nodes -subj "$TEST_CA_DN" \ + -keyout $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -newkey rsa:1024 -new \ + -out $CERTS_DIR/$TEST_CA_FILE.req.pem + +$OPENSSL_CMD x509 -req -days $DAYS \ + -in $CERTS_DIR/$TEST_CA_FILE.req.pem \ + -extfile $OPENSSL_DIR/apps/openssl.cnf \ + -extensions v3_ca \ + -signkey $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -out $CERTS_DIR/$TEST_CA_FILE.cert.pem + +# Display the certificate +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CA_FILE.cert.pem -text + +# Place the certificate and key in a common file +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CA_FILE.cert.pem -issuer -subject \ + > $COMBO_DIR/$TEST_CA_FILE.pem +$CAT $KEYS_DIR/$TEST_CA_FILE.key.pem >> $COMBO_DIR/$TEST_CA_FILE.pem + +# Remove the cert request file (no longer needed) +$RM $CERTS_DIR/$TEST_CA_FILE.req.pem + +echo "GENERATING A TEST SERVER CERTIFICATE (RSA)" +echo "==========================================" + +$OPENSSL_CMD req $OPENSSL_CNF -nodes -subj "$TEST_SERVER_DN" \ + -keyout $KEYS_DIR/$TEST_SERVER_FILE.key.pem \ + -newkey rsa:1024 -new \ + -out $CERTS_DIR/$TEST_SERVER_FILE.req.pem + +$OPENSSL_CMD x509 -req -days $DAYS \ + -in $CERTS_DIR/$TEST_SERVER_FILE.req.pem \ + -CA $CERTS_DIR/$TEST_CA_FILE.cert.pem \ + -CAkey $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -out $CERTS_DIR/$TEST_SERVER_FILE.cert.pem -CAcreateserial + +# Display the certificate +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_SERVER_FILE.cert.pem -text + +# Place the certificate and key in a common file +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_SERVER_FILE.cert.pem -issuer -subject \ + > $COMBO_DIR/$TEST_SERVER_FILE.pem +$CAT $KEYS_DIR/$TEST_SERVER_FILE.key.pem >> $COMBO_DIR/$TEST_SERVER_FILE.pem + +# Remove the cert request file (no longer needed) +$RM $CERTS_DIR/$TEST_SERVER_FILE.req.pem + +echo "GENERATING A TEST CLIENT CERTIFICATE (RSA)" +echo "==========================================" + +$OPENSSL_CMD req $OPENSSL_CNF -nodes -subj "$TEST_CLIENT_DN" \ + -keyout $KEYS_DIR/$TEST_CLIENT_FILE.key.pem \ + -newkey rsa:1024 -new \ + -out $CERTS_DIR/$TEST_CLIENT_FILE.req.pem + +$OPENSSL_CMD x509 -req -days $DAYS \ + -in $CERTS_DIR/$TEST_CLIENT_FILE.req.pem \ + -CA $CERTS_DIR/$TEST_CA_FILE.cert.pem \ + -CAkey $KEYS_DIR/$TEST_CA_FILE.key.pem \ + -out $CERTS_DIR/$TEST_CLIENT_FILE.cert.pem -CAcreateserial + +# Display the certificate +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CLIENT_FILE.cert.pem -text + +# Place the certificate and key in a common file +$OPENSSL_CMD x509 -in $CERTS_DIR/$TEST_CLIENT_FILE.cert.pem -issuer -subject \ + > $COMBO_DIR/$TEST_CLIENT_FILE.pem +$CAT $KEYS_DIR/$TEST_CLIENT_FILE.key.pem >> $COMBO_DIR/$TEST_CLIENT_FILE.pem + +# Remove the cert request file (no longer needed) +$RM $CERTS_DIR/$TEST_CLIENT_FILE.req.pem + diff --git a/demos/ssltest-ecc/ssltest.sh b/demos/ssltest-ecc/ssltest.sh new file mode 100755 index 0000000..923ca43 --- /dev/null +++ b/demos/ssltest-ecc/ssltest.sh @@ -0,0 +1,188 @@ +#! /bin/sh +# Tests ECC cipher suites using ssltest. Requires one argument which could +# be aecdh or ecdh-ecdsa or ecdhe-ecdsa or ecdh-rsa or ecdhe-rsa. +# A second optional argument can be one of ssl2 ssl3 or tls1 + +if [ "$1" = "" ]; then + (echo "Usage: $0 test [ protocol ]" + echo " where test is one of aecdh, ecdh-ecdsa, ecdhe-ecdsa, ecdh-rsa, ecdhe-rsa" + echo " and protocol (optional) is one of ssl2, ssl3, tls1" + echo "Run RSAcertgen.sh, ECC-RSAcertgen.sh, ECCcertgen.sh first." + ) >&2 + exit 1 +fi + + +OPENSSL_DIR=../.. +CERTS_DIR=./Certs +SSLTEST=$OPENSSL_DIR/test/ssltest +# SSL protocol version to test (one of ssl2 ssl3 or tls1)" +SSLVERSION= + +# These don't really require any certificates +AECDH_CIPHER_LIST="AECDH-AES256-SHA AECDH-AES128-SHA AECDH-DES-CBC3-SHA AECDH-RC4-SHA AECDH-NULL-SHA" + +# These require ECC certificates signed with ECDSA +# The EC public key must be authorized for key agreement. +ECDH_ECDSA_CIPHER_LIST="ECDH-ECDSA-AES256-SHA ECDH-ECDSA-AES128-SHA ECDH-ECDSA-DES-CBC3-SHA ECDH-ECDSA-RC4-SHA ECDH-ECDSA-NULL-SHA" + +# These require ECC certificates. +# The EC public key must be authorized for digital signature. +ECDHE_ECDSA_CIPHER_LIST="ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-DES-CBC3-SHA ECDHE-ECDSA-RC4-SHA ECDHE-ECDSA-NULL-SHA" + +# These require ECC certificates signed with RSA. +# The EC public key must be authorized for key agreement. +ECDH_RSA_CIPHER_LIST="ECDH-RSA-AES256-SHA ECDH-RSA-AES128-SHA ECDH-RSA-DES-CBC3-SHA ECDH-RSA-RC4-SHA ECDH-RSA-NULL-SHA" + +# These require RSA certificates. +# The RSA public key must be authorized for digital signature. +ECDHE_RSA_CIPHER_LIST="ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA ECDHE-RSA-DES-CBC3-SHA ECDHE-RSA-RC4-SHA ECDHE-RSA-NULL-SHA" + +# List of Elliptic curves over which we wish to test generation of +# ephemeral ECDH keys when using AECDH or ECDHE ciphers +# NOTE: secp192r1 = prime192v1 and secp256r1 = prime256v1 +#ELLIPTIC_CURVE_LIST="secp112r1 sect113r2 secp128r1 sect131r1 secp160k1 sect163r2 wap-wsg-idm-ecid-wtls7 c2pnb163v3 c2pnb176v3 c2tnb191v3 secp192r1 prime192v3 sect193r2 secp224r1 wap-wsg-idm-ecid-wtls10 sect239k1 prime239v2 secp256r1 prime256v1 sect283k1 secp384r1 sect409r1 secp521r1 sect571r1" +ELLIPTIC_CURVE_LIST="sect163k1 sect163r1 sect163r2 sect193r1 sect193r2 sect233k1 sect233r1 sect239k1 sect283k1 sect283r1 sect409k1 sect409r1 sect571k1 sect571r1 secp160k1 secp160r1 secp160r2 secp192k1 prime192v1 secp224k1 secp224r1 secp256k1 prime256v1 secp384r1 secp521r1" + +DEFAULT_CURVE="sect163r2" + +if [ "$2" = "" ]; then + if [ "$SSL_VERSION" = "" ]; then + SSL_VERSION="" + else + SSL_VERSION="-$SSL_VERSION" + fi +else + SSL_VERSION="-$2" +fi + +#============================================================== +# Anonymous cipher suites do not require key or certificate files +# but ssltest expects a cert file and complains if it can't +# open the default one. +SERVER_PEM=$OPENSSL_DIR/apps/server.pem + +if [ "$1" = "aecdh" ]; then +for cipher in $AECDH_CIPHER_LIST +do + echo "Testing $cipher" + $SSLTEST $SSL_VERSION -cert $SERVER_PEM -cipher $cipher +done +#-------------------------------------------------------------- +for curve in $ELLIPTIC_CURVE_LIST +do + echo "Testing AECDH-NULL-SHA (with $curve)" + $SSLTEST $SSL_VERSION -cert $SERVER_PEM \ + -named_curve $curve -cipher AECDH-NULL-SHA +done + +for curve in $ELLIPTIC_CURVE_LIST +do + echo "Testing AECDH-RC4-SHA (with $curve)" + $SSLTEST $SSL_VERSION -cert $SERVER_PEM \ + -named_curve $curve -cipher AECDH-RC4-SHA +done +fi + +#============================================================== +# Both ECDH-ECDSA and ECDHE-ECDSA cipher suites require +# the server to have an ECC certificate signed with ECDSA. +CA_PEM=$CERTS_DIR/secp160r1TestCA.pem +SERVER_PEM=$CERTS_DIR/secp160r2TestServer.pem +CLIENT_PEM=$CERTS_DIR/secp160r2TestClient.pem + +if [ "$1" = "ecdh-ecdsa" ]; then +for cipher in $ECDH_ECDSA_CIPHER_LIST +do + echo "Testing $cipher (with server authentication)" + $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -cipher $cipher + + echo "Testing $cipher (with server and client authentication)" + $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -c_cert $CLIENT_PEM -client_auth \ + -cipher $cipher +done +fi + +#============================================================== +if [ "$1" = "ecdhe-ecdsa" ]; then +for cipher in $ECDHE_ECDSA_CIPHER_LIST +do + echo "Testing $cipher (with server authentication)" + $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -cipher $cipher -named_curve $DEFAULT_CURVE + + echo "Testing $cipher (with server and client authentication)" + $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -c_cert $CLIENT_PEM -client_auth \ + -cipher $cipher -named_curve $DEFAULT_CURVE +done + +#-------------------------------------------------------------- +for curve in $ELLIPTIC_CURVE_LIST +do + echo "Testing ECDHE-ECDSA-AES128-SHA (2-way auth with $curve)" + $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -c_cert $CLIENT_PEM -client_auth \ + -cipher ECDHE-ECDSA-AES128-SHA -named_curve $curve +done +fi + +#============================================================== +# ECDH-RSA cipher suites require the server to have an ECC +# certificate signed with RSA. +CA_PEM=$CERTS_DIR/rsa1024TestCA.pem +SERVER_PEM=$CERTS_DIR/sect163r1-rsaTestServer.pem +CLIENT_PEM=$CERTS_DIR/sect163r1-rsaTestClient.pem + +if [ "$1" = "ecdh-rsa" ]; then +for cipher in $ECDH_RSA_CIPHER_LIST +do + echo "Testing $cipher (with server authentication)" + $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -cipher $cipher + + echo "Testing $cipher (with server and client authentication)" + $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -c_cert $CLIENT_PEM -client_auth \ + -cipher $cipher +done +fi + +#============================================================== +# ECDHE-RSA cipher suites require the server to have an RSA cert. +CA_PEM=$CERTS_DIR/rsa1024TestCA.pem +SERVER_PEM=$CERTS_DIR/rsa1024TestServer.pem +CLIENT_PEM=$CERTS_DIR/rsa1024TestClient.pem + +if [ "$1" = "ecdhe-rsa" ]; then +for cipher in $ECDHE_RSA_CIPHER_LIST +do + echo "Testing $cipher (with server authentication)" + echo $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -cipher $cipher -named_curve $DEFAULT_CURVE + $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -cipher $cipher -named_curve $DEFAULT_CURVE + + echo "Testing $cipher (with server and client authentication)" + $SSLTEST $SSL_VERSION -CAfile $CA_PEM \ + -cert $SERVER_PEM -server_auth \ + -c_cert $CLIENT_PEM -client_auth \ + -cipher $cipher -named_curve $DEFAULT_CURVE +done +fi +#============================================================== + + + + diff --git a/demos/state_machine/Makefile b/demos/state_machine/Makefile new file mode 100644 index 0000000..c7a1145 --- /dev/null +++ b/demos/state_machine/Makefile @@ -0,0 +1,9 @@ +CFLAGS=-I../../include -Wall -Werror -g + +all: state_machine + +state_machine: state_machine.o + $(CC) -o state_machine state_machine.o -L../.. -lssl -lcrypto + +test: state_machine + ./state_machine 10000 ../../apps/server.pem ../../apps/server.pem diff --git a/demos/state_machine/state_machine.c b/demos/state_machine/state_machine.c new file mode 100644 index 0000000..fef3f3e --- /dev/null +++ b/demos/state_machine/state_machine.c @@ -0,0 +1,416 @@ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* + * Nuron, a leader in hardware encryption technology, generously + * sponsored the development of this demo by Ben Laurie. + * + * See http://www.nuron.com/. + */ + +/* + * the aim of this demo is to provide a fully working state-machine + * style SSL implementation, i.e. one where the main loop acquires + * some data, then converts it from or to SSL by feeding it into the + * SSL state machine. It then does any I/O required by the state machine + * and loops. + * + * In order to keep things as simple as possible, this implementation + * listens on a TCP socket, which it expects to get an SSL connection + * on (for example, from s_client) and from then on writes decrypted + * data to stdout and encrypts anything arriving on stdin. Verbose + * commentary is written to stderr. + * + * This implementation acts as a server, but it can also be done for a client. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* die_unless is intended to work like assert, except that it happens + always, even if NDEBUG is defined. Use assert as a stopgap. */ + +#define die_unless(x) assert(x) + +typedef struct + { + SSL_CTX *pCtx; + BIO *pbioRead; + BIO *pbioWrite; + SSL *pSSL; + } SSLStateMachine; + +void SSLStateMachine_print_error(SSLStateMachine *pMachine,const char *szErr) + { + unsigned long l; + + fprintf(stderr,"%s\n",szErr); + while((l=ERR_get_error())) + { + char buf[1024]; + + ERR_error_string_n(l,buf,sizeof buf); + fprintf(stderr,"Error %lx: %s\n",l,buf); + } + } + +SSLStateMachine *SSLStateMachine_new(const char *szCertificateFile, + const char *szKeyFile) + { + SSLStateMachine *pMachine=malloc(sizeof *pMachine); + int n; + + die_unless(pMachine); + + pMachine->pCtx=SSL_CTX_new(SSLv23_server_method()); + die_unless(pMachine->pCtx); + + n=SSL_CTX_use_certificate_file(pMachine->pCtx,szCertificateFile, + SSL_FILETYPE_PEM); + die_unless(n > 0); + + n=SSL_CTX_use_PrivateKey_file(pMachine->pCtx,szKeyFile,SSL_FILETYPE_PEM); + die_unless(n > 0); + + pMachine->pSSL=SSL_new(pMachine->pCtx); + die_unless(pMachine->pSSL); + + pMachine->pbioRead=BIO_new(BIO_s_mem()); + + pMachine->pbioWrite=BIO_new(BIO_s_mem()); + + SSL_set_bio(pMachine->pSSL,pMachine->pbioRead,pMachine->pbioWrite); + + SSL_set_accept_state(pMachine->pSSL); + + return pMachine; + } + +void SSLStateMachine_read_inject(SSLStateMachine *pMachine, + const unsigned char *aucBuf,int nBuf) + { + int n=BIO_write(pMachine->pbioRead,aucBuf,nBuf); + /* If it turns out this assert fails, then buffer the data here + * and just feed it in in churn instead. Seems to me that it + * should be guaranteed to succeed, though. + */ + assert(n == nBuf); + fprintf(stderr,"%d bytes of encrypted data fed to state machine\n",n); + } + +int SSLStateMachine_read_extract(SSLStateMachine *pMachine, + unsigned char *aucBuf,int nBuf) + { + int n; + + if(!SSL_is_init_finished(pMachine->pSSL)) + { + fprintf(stderr,"Doing SSL_accept\n"); + n=SSL_accept(pMachine->pSSL); + if(n == 0) + fprintf(stderr,"SSL_accept returned zero\n"); + if(n < 0) + { + int err; + + if((err=SSL_get_error(pMachine->pSSL,n)) == SSL_ERROR_WANT_READ) + { + fprintf(stderr,"SSL_accept wants more data\n"); + return 0; + } + + SSLStateMachine_print_error(pMachine,"SSL_accept error"); + exit(7); + } + return 0; + } + + n=SSL_read(pMachine->pSSL,aucBuf,nBuf); + if(n < 0) + { + int err=SSL_get_error(pMachine->pSSL,n); + + if(err == SSL_ERROR_WANT_READ) + { + fprintf(stderr,"SSL_read wants more data\n"); + return 0; + } + + SSLStateMachine_print_error(pMachine,"SSL_read error"); + exit(8); + } + + fprintf(stderr,"%d bytes of decrypted data read from state machine\n",n); + return n; + } + +int SSLStateMachine_write_can_extract(SSLStateMachine *pMachine) + { + int n=BIO_pending(pMachine->pbioWrite); + if(n) + fprintf(stderr,"There is encrypted data available to write\n"); + else + fprintf(stderr,"There is no encrypted data available to write\n"); + + return n; + } + +int SSLStateMachine_write_extract(SSLStateMachine *pMachine, + unsigned char *aucBuf,int nBuf) + { + int n; + + n=BIO_read(pMachine->pbioWrite,aucBuf,nBuf); + fprintf(stderr,"%d bytes of encrypted data read from state machine\n",n); + return n; + } + +void SSLStateMachine_write_inject(SSLStateMachine *pMachine, + const unsigned char *aucBuf,int nBuf) + { + int n=SSL_write(pMachine->pSSL,aucBuf,nBuf); + /* If it turns out this assert fails, then buffer the data here + * and just feed it in in churn instead. Seems to me that it + * should be guaranteed to succeed, though. + */ + assert(n == nBuf); + fprintf(stderr,"%d bytes of unencrypted data fed to state machine\n",n); + } + +int OpenSocket(int nPort) + { + int nSocket; + struct sockaddr_in saServer; + struct sockaddr_in saClient; + int one=1; + int nSize; + int nFD; + int nLen; + + nSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if(nSocket < 0) + { + perror("socket"); + exit(1); + } + + if(setsockopt(nSocket,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof one) < 0) + { + perror("setsockopt"); + exit(2); + } + + memset(&saServer,0,sizeof saServer); + saServer.sin_family=AF_INET; + saServer.sin_port=htons(nPort); + nSize=sizeof saServer; + if(bind(nSocket,(struct sockaddr *)&saServer,nSize) < 0) + { + perror("bind"); + exit(3); + } + + if(listen(nSocket,512) < 0) + { + perror("listen"); + exit(4); + } + + nLen=sizeof saClient; + nFD=accept(nSocket,(struct sockaddr *)&saClient,&nLen); + if(nFD < 0) + { + perror("accept"); + exit(5); + } + + fprintf(stderr,"Incoming accepted on port %d\n",nPort); + + return nFD; + } + +int main(int argc,char **argv) + { + SSLStateMachine *pMachine; + int nPort; + int nFD; + const char *szCertificateFile; + const char *szKeyFile; + char rbuf[1]; + int nrbuf=0; + + if(argc != 4) + { + fprintf(stderr,"%s \n",argv[0]); + exit(6); + } + + nPort=atoi(argv[1]); + szCertificateFile=argv[2]; + szKeyFile=argv[3]; + + SSL_library_init(); + OpenSSL_add_ssl_algorithms(); + SSL_load_error_strings(); + ERR_load_crypto_strings(); + + nFD=OpenSocket(nPort); + + pMachine=SSLStateMachine_new(szCertificateFile,szKeyFile); + + for( ; ; ) + { + fd_set rfds,wfds; + unsigned char buf[1024]; + int n; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + /* Select socket for input */ + FD_SET(nFD,&rfds); + + /* check whether there's decrypted data */ + if(!nrbuf) + nrbuf=SSLStateMachine_read_extract(pMachine,rbuf,1); + + /* if there's decrypted data, check whether we can write it */ + if(nrbuf) + FD_SET(1,&wfds); + + /* Select socket for output */ + if(SSLStateMachine_write_can_extract(pMachine)) + FD_SET(nFD,&wfds); + + /* Select stdin for input */ + FD_SET(0,&rfds); + + /* Wait for something to do something */ + n=select(nFD+1,&rfds,&wfds,NULL,NULL); + assert(n > 0); + + /* Socket is ready for input */ + if(FD_ISSET(nFD,&rfds)) + { + n=read(nFD,buf,sizeof buf); + if(n == 0) + { + fprintf(stderr,"Got EOF on socket\n"); + exit(0); + } + assert(n > 0); + + SSLStateMachine_read_inject(pMachine,buf,n); + } + + /* stdout is ready for output (and hence we have some to send it) */ + if(FD_ISSET(1,&wfds)) + { + assert(nrbuf == 1); + buf[0]=rbuf[0]; + nrbuf=0; + + n=SSLStateMachine_read_extract(pMachine,buf+1,sizeof buf-1); + if(n < 0) + { + SSLStateMachine_print_error(pMachine,"read extract failed"); + break; + } + assert(n >= 0); + ++n; + if(n > 0) /* FIXME: has to be true now */ + { + int w; + + w=write(1,buf,n); + /* FIXME: we should push back any unwritten data */ + assert(w == n); + } + } + + /* Socket is ready for output (and therefore we have output to send) */ + if(FD_ISSET(nFD,&wfds)) + { + int w; + + n=SSLStateMachine_write_extract(pMachine,buf,sizeof buf); + assert(n > 0); + + w=write(nFD,buf,n); + /* FIXME: we should push back any unwritten data */ + assert(w == n); + } + + /* Stdin is ready for input */ + if(FD_ISSET(0,&rfds)) + { + n=read(0,buf,sizeof buf); + if(n == 0) + { + fprintf(stderr,"Got EOF on stdin\n"); + exit(0); + } + assert(n > 0); + + SSLStateMachine_write_inject(pMachine,buf,n); + } + } + /* not reached */ + return 0; + } diff --git a/demos/tunala/A-client.pem b/demos/tunala/A-client.pem new file mode 100644 index 0000000..a4caf6e --- /dev/null +++ b/demos/tunala/A-client.pem @@ -0,0 +1,84 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=NZ, L=Wellington, O=Really Irresponsible Authorisation Authority (RIAA), OU=Cert-stamping, CN=Jackov al-Trades/Email=none@fake.domain + Validity + Not Before: Jan 16 05:19:30 2002 GMT + Not After : Jan 14 05:19:30 2012 GMT + Subject: C=NZ, L=Auckland, O=Mordor, OU=SSL grunt things, CN=tunala-client/Email=client@fake.domain + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b0:d3:56:5c:c8:7f:fb:f4:95:9d:04:84:4f:82: + b7:a2:75:5c:81:48:8c:56:5d:52:ee:38:e1:5c:c8: + 9a:70:8e:72:f2:00:1c:17:ef:df:b7:06:59:82:04: + f1:f6:49:11:12:a6:4d:cb:1e:ed:ac:59:1c:4a:d0: + 3d:de:e6:f2:8d:cd:39:c2:0f:e0:46:2f:db:cb:9f: + 47:f7:56:e7:f8:16:5f:68:71:fb:3a:e3:ab:d2:e5: + 05:b7:da:65:61:fe:6d:30:e4:12:a8:b5:c1:71:24: + 6b:aa:80:05:41:17:a0:8b:6e:8b:e6:04:cf:85:7b: + 2a:ac:a1:79:7d:f4:96:6e:77 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + F8:43:CB:4F:4D:4F:BC:6E:52:1A:FD:F9:7B:E1:12:3F:A7:A3:BA:93 + X509v3 Authority Key Identifier: + keyid:49:FB:45:72:12:C4:CC:E1:45:A1:D3:08:9E:95:C4:2C:6D:55:3F:17 + DirName:/C=NZ/L=Wellington/O=Really Irresponsible Authorisation Authority (RIAA)/OU=Cert-stamping/CN=Jackov al-Trades/Email=none@fake.domain + serial:00 + + Signature Algorithm: md5WithRSAEncryption + 8f:5f:0e:43:da:9d:61:43:7e:03:38:9a:e6:50:9d:42:e8:95: + 34:49:75:ec:04:8d:5c:85:99:94:70:a0:e7:1f:1e:a0:8b:0f: + d6:e2:cb:f7:35:d9:96:72:bd:a6:e9:8d:4e:b1:e2:ac:97:7f: + 2f:70:01:9d:aa:04:bc:d4:01:2b:63:77:a5:de:63:3c:a8:f5: + f2:72:af:ec:11:12:c0:d4:70:cf:71:a6:fb:e9:1d:b3:27:07: + aa:f2:b1:f3:87:d6:ab:8b:ce:c2:08:1b:3c:f9:ba:ff:77:71: + 86:09:ef:9e:4e:04:06:63:44:e9:93:20:90:c7:2d:50:c6:50: + f8:66 +-----BEGIN CERTIFICATE----- +MIID9TCCA16gAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox +EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp +YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy +dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3 +DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTE5MzBaFw0xMjAxMTQw +NTE5MzBaMIGHMQswCQYDVQQGEwJOWjERMA8GA1UEBxMIQXVja2xhbmQxDzANBgNV +BAoTBk1vcmRvcjEZMBcGA1UECxMQU1NMIGdydW50IHRoaW5nczEWMBQGA1UEAxMN +dHVuYWxhLWNsaWVudDEhMB8GCSqGSIb3DQEJARYSY2xpZW50QGZha2UuZG9tYWlu +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw01ZcyH/79JWdBIRPgreidVyB +SIxWXVLuOOFcyJpwjnLyABwX79+3BlmCBPH2SRESpk3LHu2sWRxK0D3e5vKNzTnC +D+BGL9vLn0f3Vuf4Fl9ocfs646vS5QW32mVh/m0w5BKotcFxJGuqgAVBF6CLbovm +BM+FeyqsoXl99JZudwIDAQABo4IBQDCCATwwCQYDVR0TBAIwADAsBglghkgBhvhC +AQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFPhD +y09NT7xuUhr9+XvhEj+no7qTMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzhRaHTCJ6V +xCxtVT8XoYG6pIG3MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3Rv +bjE8MDoGA1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBB +dXRob3JpdHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQD +ExBKYWNrb3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9t +YWluggEAMA0GCSqGSIb3DQEBBAUAA4GBAI9fDkPanWFDfgM4muZQnULolTRJdewE +jVyFmZRwoOcfHqCLD9biy/c12ZZyvabpjU6x4qyXfy9wAZ2qBLzUAStjd6XeYzyo +9fJyr+wREsDUcM9xpvvpHbMnB6rysfOH1quLzsIIGzz5uv93cYYJ755OBAZjROmT +IJDHLVDGUPhm +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQCw01ZcyH/79JWdBIRPgreidVyBSIxWXVLuOOFcyJpwjnLyABwX +79+3BlmCBPH2SRESpk3LHu2sWRxK0D3e5vKNzTnCD+BGL9vLn0f3Vuf4Fl9ocfs6 +46vS5QW32mVh/m0w5BKotcFxJGuqgAVBF6CLbovmBM+FeyqsoXl99JZudwIDAQAB +AoGAU4chbqbPvkclPYzaq2yGLlneHrwUft+KwzlfS6L/QVgo+CQRIUWQmjaHpaGM +YtjVFcg1S1QK1bUqZjTEZT0XKhfbYmqW8yYTfbcDEbnY7esoYlvIlW8qRlPRlTBE +utKrtZafmVhLgoNawYGD0aLZofPqpYjbGUlrC7nrem2vNJECQQDVLD3Qb+OlEMET +73ApnJhYsK3e+G2LTrtjrS8y5zS4+Xv61XUqvdV7ogzRl0tpvSAmMOItVyoYadkB +S3xSIWX9AkEA1Fm1FhkQSZwGG5rf4c6gMN71jJ6JE3/kocdVa0sUjRevIupo4XQ2 +Vkykxi84MRP8cfHqyjewq7Ozv3op2MGWgwJBAKemsb66IJjzAkaBav7u70nhOf0/ ++Dc1Zl7QF2y7NVW8sGrnccx5m+ot2lMD4AV6/kvK6jaqdKrapBZGnbGiHqkCQQDI +T1r33mqz1R8Z2S2Jtzz6/McKf930a/dC+GLGVEutkILf39lRmytKmv/wB0jtWtoO +rlJ5sLDSNzC+1cE1u997AkEAu3IrtGmLKiuS6kDj6W47m+iiTIsuSJtTJb1SbUaK +fIoBNFxbvJYW6rUU9+PxpMRaEhzh5s24/jBOE+mlb17mRQ== +-----END RSA PRIVATE KEY----- diff --git a/demos/tunala/A-server.pem b/demos/tunala/A-server.pem new file mode 100644 index 0000000..e9f37b1 --- /dev/null +++ b/demos/tunala/A-server.pem @@ -0,0 +1,84 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=NZ, L=Wellington, O=Really Irresponsible Authorisation Authority (RIAA), OU=Cert-stamping, CN=Jackov al-Trades/Email=none@fake.domain + Validity + Not Before: Jan 16 05:14:06 2002 GMT + Not After : Jan 14 05:14:06 2012 GMT + Subject: C=NZ, L=Wellington, O=Middle Earth, OU=SSL dev things, CN=tunala-server/Email=server@fake.domain + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a9:3e:62:87:97:13:6b:de:8f:bc:1d:0a:3f:65: + 0c:f9:76:a3:53:ce:97:30:27:0d:c6:df:72:1f:8d: + 5a:ce:58:23:6a:65:e5:e3:72:1a:8d:7f:fe:90:01: + ea:42:f1:9f:6e:7b:0a:bd:eb:52:15:7b:f4:3d:9c: + 4e:db:74:29:2b:d1:81:9d:b9:9e:18:2b:87:e1:da: + 50:20:3c:59:6c:c9:83:3e:2c:11:0b:78:1e:03:f4: + 56:3a:db:95:6a:75:33:85:a9:7b:cc:3c:4a:67:96: + f2:24:b2:a0:cb:2e:cc:52:18:16:6f:44:d9:29:64: + 07:2e:fb:56:cc:7c:dc:a2:d7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 70:AC:7A:B5:6E:97:C2:82:AF:11:9E:32:CB:8D:48:49:93:B7:DC:22 + X509v3 Authority Key Identifier: + keyid:49:FB:45:72:12:C4:CC:E1:45:A1:D3:08:9E:95:C4:2C:6D:55:3F:17 + DirName:/C=NZ/L=Wellington/O=Really Irresponsible Authorisation Authority (RIAA)/OU=Cert-stamping/CN=Jackov al-Trades/Email=none@fake.domain + serial:00 + + Signature Algorithm: md5WithRSAEncryption + 2e:cb:a3:cd:6d:a8:9d:d1:dc:e5:f0:e0:27:7e:4b:5a:90:a8: + 85:43:f0:05:f7:04:43:d7:5f:d1:a5:8f:5c:58:eb:fc:da:c6: + 7c:e0:0b:2b:98:72:95:f6:79:48:96:7a:fa:0c:6b:09:ec:c6: + 8c:91:74:45:9f:8f:0f:16:78:e3:66:14:fa:1e:f4:f0:23:ec: + cd:a9:52:77:20:4d:c5:05:2c:52:b6:7b:f3:42:33:fd:90:1f: + 3e:88:6f:9b:23:61:c8:80:3b:e6:57:84:2e:f7:26:c7:35:ed: + 00:8b:08:30:9b:aa:21:83:b6:6d:b8:7c:8a:9b:2a:ef:79:3d: + 96:31 +-----BEGIN CERTIFICATE----- +MIID+zCCA2SgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox +EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp +YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy +dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3 +DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTE0MDZaFw0xMjAxMTQw +NTE0MDZaMIGNMQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjEVMBMG +A1UEChMMTWlkZGxlIEVhcnRoMRcwFQYDVQQLEw5TU0wgZGV2IHRoaW5nczEWMBQG +A1UEAxMNdHVuYWxhLXNlcnZlcjEhMB8GCSqGSIb3DQEJARYSc2VydmVyQGZha2Uu +ZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpPmKHlxNr3o+8HQo/ +ZQz5dqNTzpcwJw3G33IfjVrOWCNqZeXjchqNf/6QAepC8Z9uewq961IVe/Q9nE7b +dCkr0YGduZ4YK4fh2lAgPFlsyYM+LBELeB4D9FY625VqdTOFqXvMPEpnlvIksqDL +LsxSGBZvRNkpZAcu+1bMfNyi1wIDAQABo4IBQDCCATwwCQYDVR0TBAIwADAsBglg +hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O +BBYEFHCserVul8KCrxGeMsuNSEmTt9wiMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzh +RaHTCJ6VxCxtVT8XoYG6pIG3MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2Vs +bGluZ3RvbjE8MDoGA1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNh +dGlvbiBBdXRob3JpdHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkw +FwYDVQQDExBKYWNrb3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZh +a2UuZG9tYWluggEAMA0GCSqGSIb3DQEBBAUAA4GBAC7Lo81tqJ3R3OXw4Cd+S1qQ +qIVD8AX3BEPXX9Glj1xY6/zaxnzgCyuYcpX2eUiWevoMawnsxoyRdEWfjw8WeONm +FPoe9PAj7M2pUncgTcUFLFK2e/NCM/2QHz6Ib5sjYciAO+ZXhC73Jsc17QCLCDCb +qiGDtm24fIqbKu95PZYx +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCpPmKHlxNr3o+8HQo/ZQz5dqNTzpcwJw3G33IfjVrOWCNqZeXj +chqNf/6QAepC8Z9uewq961IVe/Q9nE7bdCkr0YGduZ4YK4fh2lAgPFlsyYM+LBEL +eB4D9FY625VqdTOFqXvMPEpnlvIksqDLLsxSGBZvRNkpZAcu+1bMfNyi1wIDAQAB +AoGANCwqHZhiAU/TyW6+WPqivEhpYw19p/dyFMuPF9DwnEmpaUROUQY8z0AUznn4 +qHhp6Jn/nrprTHowucl0ucweYIYVxZoUiUDFpxdFUbzMdFvo6HcyV1Pe4Rt81HaY +KYWrTZ6PaPtN65hLms8NhPEdGcGAFlY1owYv4QNGq2bU1JECQQDd32LM0NSfyGmK +4ziajqGcvzK9NO2XyV/nJsGlJZNgMh2zm1t7yR28l/6Q2uyU49cCN+2aYULZCAfs +taNvxBspAkEAw0alNub+xj2AVQvaxOB1sGfKzsJjHCzKIxUXn/tJi3j0+2asmkBZ +Umx1MWr9jKQBnCMciCRUbnMEZiElOxCN/wJAfAeQl6Z19gx206lJzzzEo3dOye54 +k02DSxijT8q9pBzf9bN3ZK987BybtiZr8p+bZiYVsSOF1wViSLURdD1QYQJAIaMU +qH1n24wShBPTrmAfxbBLTgxL+Dl65Eoo1KT7iSvfv0JzbuqwuDL4iPeuD0DdCiE+ +M/FWHeRwGIuTFzaFzwJBANKwx0jZS/h093w9g0Clw6UzeA1P5VcAt9y+qMC9hO3c +4KXwIxQAt9yRaFLpiIR9do5bjjKNnMguf3aO/XRSDQM= +-----END RSA PRIVATE KEY----- diff --git a/demos/tunala/CA.pem b/demos/tunala/CA.pem new file mode 100644 index 0000000..7a55b54 --- /dev/null +++ b/demos/tunala/CA.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID9zCCA2CgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox +EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp +YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy +dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3 +DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTA5NTlaFw0xMjAxMTQw +NTA5NTlaMIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoG +A1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3Jp +dHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNr +b3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluMIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7QdDfFIrJn3X24hKmpkyk3TG0Ivxd +K2wWmDPXq1wjr8lUTwrA6hM5Ba9N36jLieWpXhviLOWu9DBza5GmtgCuXloATKTC +94xOdKHlciTVujG3wDlLDB5e710Kar84nnj6VueL1RyZ0bmP5PANa4mbGW9Tqc7J +CkBTTW2y9d0SgQIDAQABo4IBFTCCAREwHQYDVR0OBBYEFEn7RXISxMzhRaHTCJ6V +xCxtVT8XMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzhRaHTCJ6VxCxtVT8XoYG6pIG3 +MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoGA1UEChMz +UmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3JpdHkgKFJJ +QUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNrb3YgYWwt +VHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluggEAMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAYQo95V/NY+eKxYxkhibZiUQygph+ +gTfgbDG20MsnH6+8//w5ArHauFCgDrf0P2VyACgq+N4pBTWFGaAaLwbjKy9HCe2E +j9C91tO1CqDS4MJkDB5AP13FTkK6fP1ZCiTQranOAp3DlGWTTWsFVyW5kVfQ9diS +ZOyJZ9Fit5XM2X0= +-----END CERTIFICATE----- diff --git a/demos/tunala/INSTALL b/demos/tunala/INSTALL new file mode 100644 index 0000000..a65bbeb --- /dev/null +++ b/demos/tunala/INSTALL @@ -0,0 +1,107 @@ +There are two ways to build this code; + +(1) Manually + +(2) Using all-singing all-dancing (all-confusing) autotools, ie. autoconf, +automake, and their little friends (autoheader, etc). + +================= +Building Manually +================= + +There is a basic "Makefile" in this directory that gets moved out of the way and +ignored when building with autoconf et al. This Makefile is suitable for +building tunala on Linux using gcc. Any other platform probably requires some +tweaking. Here are the various bits you might need to do if you want to build +this way and the default Makefile isn't sufficient; + +* Compiler: Edit the "CC" definition in Makefile + +* Headers, features: tunala.h controls what happens in the non-autoconf world. + It, by default, assumes the system has *everything* (except autoconf's + "config.h") so if a target system is missing something it must define the + appropriate "NO_***" symbols in CFLAGS. These include; + + - NO_HAVE_UNISTD_H, NO_HAVE_FCNTL_H, NO_HAVE_LIMITS_H + Indicates the compiling system doesn't have (or need) these header files. + - NO_HAVE_STRSTR, NO_HAVE_STRTOUL + Indicates the compiling system doesn't have these functions. Replacements + are compiled and used in breakage.c + - NO_HAVE_SELECT, NO_HAVE_SOCKET + Pointless symbols - these indicate select() and/or socket() are missing in + which case the program won't compile anyway. + + If you want to specify any of these, add them with "-D" prefixed to each in + the CFLAGS definition in Makefile. + +* Compilation flags: edit DEBUG_FLAGS and/or CFLAGS directly to control the + flags passed to the compiler. This can also be used to change the degree of + optimisation. + +* Linker flags: some systems (eg. Solaris) require extra linker flags such as; + -ldl, -lsocket, -lnsl, etc. If unsure, bring up the man page for whichever + function is "undefined" when the linker fails - that usually indicates what + you need to add. Make changes to the LINK_FLAGS symbol. + +* Linker command: if a different linker syntax or even a different program is + required to link, edit the linker line directly in the "tunala:" target + definition - it currently assumes the "CC" (compiler) program is used to link. + +====================== +Building Automagically +====================== + +Automagic building is handled courtesy of autoconf, automake, etc. There are in +fact two steps required to build, and only the first has to be done on a system +with these tools installed (and if I was prepared to bloat out the CVS +repository, I could store these extra files, but I'm not). + +First step: "autogunk.sh" +------------------------- + +The "./autogunk.sh" script will call all the necessary autotool commands to +create missing files and run automake and autoconf. The result is that a +"./configure" script should be generated and a "Makefile.in" generated from the +supplied "Makefile.am". NB: This script also moves the "manual" Makefile (see +above) out of the way and calls it "Makefile.plain" - the "ungunk" script +reverses this to leave the directory it was previously. + +Once "ungunk" has been run, the resulting directory should be able to build on +other systems without autoconf, automake, or libtool. Which is what the second +step describes; + +Second step: "./configure" +-------------------------- + +The second step is to run the generated "./configure" script to create a +config.h header for your system and to generate a "Makefile" (generated from +"Makefile.in") tweaked to compile on your system. This is the standard sort of +thing you see in GNU packages, for example, and the standard tricks also work. +Eg. to override "configure"'s choice of compiler, set the CC environment +variable prior to running configure, eg. + + CC=gcc ./configure + +would cause "gcc" to be used even if there is an otherwise preferable (to +autoconf) native compiler on your system. + +After this run "make" and it should build the "tunala" executable. + +Notes +----- + +- Some versions of autoconf (or automake?) generate a Makefile syntax that gives + trouble to some "make" programs on some systems (eg. OpenBSD). If this + happens, either build 'Manually' (see above) or use "gmake" instead of "make". + I don't like this either but like even less the idea of sifting into all the + script magic crud that's involved. + +- On a solaris system I tried, the "configure" script specified some broken + compiler flags in the resulting Makefile that don't even get echoed to + stdout/err when the error happens (evil!). If this happens, go into the + generated Makefile, find the two affected targets ("%.o:" and "%.lo"), and + remove the offending hidden option in the $(COMPILE) line all the sludge after + the two first lines of script (ie. after the "echo" and the "COMPILE" lines). + NB: This will probably only function if "--disable-shared" was used, otherwise + who knows what would result ... + diff --git a/demos/tunala/Makefile b/demos/tunala/Makefile new file mode 100644 index 0000000..bef1704 --- /dev/null +++ b/demos/tunala/Makefile @@ -0,0 +1,41 @@ +# Edit these to suit +# +# Oh yeah, and please read the README too. + + +SSL_HOMEDIR=../.. +SSL_INCLUDEDIR=$(SSL_HOMEDIR)/include +SSL_LIBDIR=$(SSL_HOMEDIR) + +RM=rm -f +CC=gcc +DEBUG_FLAGS=-g -ggdb3 -Wall -Wshadow +INCLUDE_FLAGS=-I$(SSL_INCLUDEDIR) +CFLAGS=$(DEBUG_FLAGS) $(INCLUDE_FLAGS) -DNO_CONFIG_H +COMPILE=$(CC) $(CFLAGS) -c + +# Edit, particularly the "-ldl" if not building with "dlfcn" support +LINK_FLAGS=-L$(SSL_LIBDIR) -lssl -lcrypto -ldl + +SRCS=buffer.c cb.c ip.c sm.c tunala.c breakage.c +OBJS=buffer.o cb.o ip.o sm.o tunala.o breakage.o + +TARGETS=tunala + +default: $(TARGETS) + +clean: + $(RM) $(OBJS) $(TARGETS) *.bak core + +.c.o: + $(COMPILE) $< + +tunala: $(OBJS) + $(CC) -o tunala $(OBJS) $(LINK_FLAGS) + +# Extra dependencies, should really use makedepend +buffer.o: buffer.c tunala.h +cb.o: cb.c tunala.h +ip.o: ip.c tunala.h +sm.o: sm.c tunala.h +tunala.o: tunala.c tunala.h diff --git a/demos/tunala/Makefile.am b/demos/tunala/Makefile.am new file mode 100644 index 0000000..706c780 --- /dev/null +++ b/demos/tunala/Makefile.am @@ -0,0 +1,7 @@ +# Our includes come from the OpenSSL build-tree we're in +INCLUDES = -I$(top_builddir)/../../include + +bin_PROGRAMS = tunala + +tunala_SOURCES = tunala.c buffer.c cb.c ip.c sm.c breakage.c +tunala_LDADD = -L$(top_builddir)/../.. -lssl -lcrypto diff --git a/demos/tunala/README b/demos/tunala/README new file mode 100644 index 0000000..1569008 --- /dev/null +++ b/demos/tunala/README @@ -0,0 +1,233 @@ +This is intended to be an example of a state-machine driven SSL application. It +acts as an SSL tunneler (functioning as either the server or client half, +depending on command-line arguments). *PLEASE* read the comments in tunala.h +before you treat this stuff as anything more than a curiosity - YOU HAVE BEEN +WARNED!! There, that's the draconian bit out of the way ... + + +Why "tunala"?? +-------------- + +I thought I asked you to read tunala.h?? :-) + + +Show me +------- + +If you want to simply see it running, skip to the end and see some example +command-line arguments to demonstrate with. + + +Where to look and what to do? +----------------------------- + +The code is split up roughly coinciding with the detaching of an "abstract" SSL +state machine (which is the purpose of all this) and its surrounding application +specifics. This is primarily to make it possible for me to know when I could cut +corners and when I needed to be rigorous (or at least maintain the pretense as +such :-). + +Network stuff: + +Basically, the network part of all this is what is supposed to be abstracted out +of the way. The intention is to illustrate one way to stick OpenSSL's mechanisms +inside a little memory-driven sandbox and operate it like a pure state-machine. +So, the network code is inside both ip.c (general utility functions and gory +IPv4 details) and tunala.c itself, which takes care of application specifics +like the main select() loop. The connectivity between the specifics of this +application (TCP/IP tunneling and the associated network code) and the +underlying abstract SSL state machine stuff is through the use of the "buffer_t" +type, declared in tunala.h and implemented in buffer.c. + +State machine: + +Which leaves us, generally speaking, with the abstract "state machine" code left +over and this is sitting inside sm.c, with declarations inside tunala.h. As can +be seen by the definition of the state_machine_t structure and the associated +functions to manipulate it, there are the 3 OpenSSL "handles" plus 4 buffer_t +structures dealing with IO on both the encrypted and unencrypted sides ("dirty" +and "clean" respectively). The "SSL" handle is what facilitates the reading and +writing of the unencrypted (tunneled) data. The two "BIO" handles act as the +read and write channels for encrypted tunnel traffic - in other applications +these are often socket BIOs so that the OpenSSL framework operates with the +network layer directly. In this example, those two BIOs are memory BIOs +(BIO_s_mem()) so that the sending and receiving of the tunnel traffic stays +within the state-machine, and we can handle where this gets send to (or read +from) ourselves. + + +Why? +---- + +If you take a look at the "state_machine_t" section of tunala.h and the code in +sm.c, you will notice that nothing related to the concept of 'transport' is +involved. The binding to TCP/IP networking occurs in tunala.c, specifically +within the "tunala_item_t" structure that associates a state_machine_t object +with 4 file-descriptors. The way to best see where the bridge between the +outside world (TCP/IP reads, writes, select()s, file-descriptors, etc) and the +state machine is, is to examine the "tunala_item_io()" function in tunala.c. +This is currently around lines 641-732 but of course could be subject to change. + + +And...? +------- + +Well, although that function is around 90 lines of code, it could easily have +been a lot less only I was trying to address an easily missed "gotcha" (item (2) +below). The main() code that drives the select/accept/IO loop initialises new +tunala_item_t structures when connections arrive, and works out which +file-descriptors go where depending on whether we're an SSL client or server +(client --> accepted connection is clean and proxied is dirty, server --> +accepted connection is dirty and proxied is clean). What that tunala_item_io() +function is attempting to do is 2 things; + + (1) Perform all reads and writes on the network directly into the + state_machine_t's buffers (based on a previous select() result), and only + then allow the abstact state_machine_t to "churn()" using those buffers. + This will cause the SSL machine to consume as much input data from the two + "IN" buffers as possible, and generate as much output data into the two + "OUT" buffers as possible. Back up in the main() function, the next main + loop loop will examine these output buffers and select() for writability + on the corresponding sockets if the buffers are non-empty. + + (2) Handle the complicated tunneling-specific issue of cascading "close"s. + This is the reason for most of the complexity in the logic - if one side + of the tunnel is closed, you can't simply close the other side and throw + away the whole thing - (a) there may still be outgoing data on the other + side of the tunnel that hasn't been sent yet, (b) the close (or things + happening during the close) may cause more data to be generated that needs + sending on the other side. Of course, this logic is complicated yet futher + by the fact that it's different depending on which side closes first :-) + state_machine_close_clean() will indicate to the state machine that the + unencrypted side of the tunnel has closed, so any existing outgoing data + needs to be flushed, and the SSL stream needs to be closed down using the + appropriate shutdown sequence. state_machine_close_dirty() is simpler + because it indicates that the SSL stream has been disconnected, so all + that remains before closing the other side is to flush out anything that + remains and wait for it to all be sent. + +Anyway, with those things in mind, the code should be a little easier to follow +in terms of "what is *this* bit supposed to achieve??!!". + + +How might this help? +-------------------- + +Well, the reason I wrote this is that there seemed to be rather a flood of +questions of late on the openssl-dev and openssl-users lists about getting this +whole IO logic thing sorted out, particularly by those who were trying to either +use non-blocking IO, or wanted SSL in an environment where "something else" was +handling the network already and they needed to operate in memory only. This +code is loosely based on some other stuff I've been working on, although that +stuff is far more complete, far more dependant on a whole slew of other +network/framework code I don't want to incorporate here, and far harder to look +at for 5 minutes and follow where everything is going. I will be trying over +time to suck in a few things from that into this demo in the hopes it might be +more useful, and maybe to even make this demo usable as a utility of its own. +Possible things include: + + * controlling multiple processes/threads - this can be used to combat + latencies and get passed file-descriptor limits on some systems, and it uses + a "controller" process/thread that maintains IPC links with the + processes/threads doing the real work. + + * cert verification rules - having some say over which certs get in or out :-) + + * control over SSL protocols and cipher suites + + * A few other things you can already do in s_client and s_server :-) + + * Support (and control over) session resuming, particularly when functioning + as an SSL client. + +If you have a particular environment where this model might work to let you "do +SSL" without having OpenSSL be aware of the transport, then you should find you +could use the state_machine_t structure (or your own variant thereof) and hook +it up to your transport stuff in much the way tunala.c matches it up with those +4 file-descriptors. The state_machine_churn(), state_machine_close_clean(), and +state_machine_close_dirty() functions are the main things to understand - after +that's done, you just have to ensure you're feeding and bleeding the 4 +state_machine buffers in a logical fashion. This state_machine loop handles not +only handshakes and normal streaming, but also renegotiates - there's no special +handling required beyond keeping an eye on those 4 buffers and keeping them in +sync with your outer "loop" logic. Ie. if one of the OUT buffers is not empty, +you need to find an opportunity to try and forward its data on. If one of the IN +buffers is not full, you should keep an eye out for data arriving that should be +placed there. + +This approach could hopefully also allow you to run the SSL protocol in very +different environments. As an example, you could support encrypted event-driven +IPC where threads/processes pass messages to each other inside an SSL layer; +each IPC-message's payload would be in fact the "dirty" content, and the "clean" +payload coming out of the tunnel at each end would be the real intended message. +Likewise, this could *easily* be made to work across unix domain sockets, or +even entirely different network/comms protocols. + +This is also a quick and easy way to do VPN if you (and the remote network's +gateway) support virtual network devices that are encapsulted in a single +network connection, perhaps PPP going through an SSL tunnel? + + +Suggestions +----------- + +Please let me know if you find this useful, or if there's anything wrong or +simply too confusing about it. Patches are also welcome, but please attach a +description of what it changes and why, and "diff -urN" format is preferred. +Mail to geoff@openssl.org should do the trick. + + +Example +------- + +Here is an example of how to use "tunala" ... + +First, it's assumed that OpenSSL has already built, and that you are building +inside the ./demos/tunala/ directory. If not - please correct the paths and +flags inside the Makefile. Likewise, if you want to tweak the building, it's +best to try and do so in the makefile (eg. removing the debug flags and adding +optimisation flags). + +Secondly, this code has mostly only been tested on Linux. However, some +autoconf/etc support has been added and the code has been compiled on openbsd +and solaris using that. + +Thirdly, if you are Win32, you probably need to do some *major* rewriting of +ip.c to stand a hope in hell. Good luck, and please mail me the diff if you do +this, otherwise I will take a look at another time. It can certainly be done, +but it's very non-POSIXy. + +See the INSTALL document for details on building. + +Now, if you don't have an executable "tunala" compiled, go back to "First,...". +Rinse and repeat. + +Inside one console, try typing; + +(i) ./tunala -listen localhost:8080 -proxy localhost:8081 -cacert CA.pem \ + -cert A-client.pem -out_totals -v_peer -v_strict + +In another console, type; + +(ii) ./tunala -listen localhost:8081 -proxy localhost:23 -cacert CA.pem \ + -cert A-server.pem -server 1 -out_totals -v_peer -v_strict + +Now if you open another console and "telnet localhost 8080", you should be +tunneled through to the telnet service on your local machine (if it's running - +you could change it to port "22" and tunnel ssh instead if you so desired). When +you logout of the telnet session, the tunnel should cleanly shutdown and show +you some traffic stats in both consoles. Feel free to experiment. :-) + +Notes: + + - the format for the "-listen" argument can skip the host part (eg. "-listen + 8080" is fine). If you do, the listening socket will listen on all interfaces + so you can connect from other machines for example. Using the "localhost" + form listens only on 127.0.0.1 so you can only connect locally (unless, of + course, you've set up weird stuff with your networking in which case probably + none of the above applies). + + - ./tunala -? gives you a list of other command-line options, but tunala.c is + also a good place to look :-) + + diff --git a/demos/tunala/autogunk.sh b/demos/tunala/autogunk.sh new file mode 100755 index 0000000..c9783c6 --- /dev/null +++ b/demos/tunala/autogunk.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +# This script tries to follow the "GNU way" w.r.t. the autobits. +# This does of course generate a number of irritating files. +# Try to get over it (I am getting there myself). + +# This should generate any missing crud, and then run autoconf which should turn +# configure.in into a "./configure" script and "Makefile.am" into a +# "Makefile.in". Then running "./configure" should turn "Makefile.in" into +# "Makefile" and should generate the config.h containing your systems various +# settings. I know ... what a hassle ... + +# Also, sometimes these autobits things generate bizarre output (looking like +# errors). So I direct everything "elsewhere" ... + +(aclocal +autoheader +libtoolize --copy --force +automake --foreign --add-missing --copy +autoconf) 1> /dev/null 2>&1 + +# Move the "no-autotools" Makefile out of the way +if test ! -f Makefile.plain; then + mv Makefile Makefile.plain +fi diff --git a/demos/tunala/autoungunk.sh b/demos/tunala/autoungunk.sh new file mode 100755 index 0000000..2179088 --- /dev/null +++ b/demos/tunala/autoungunk.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# This script tries to clean up as much as is possible from whatever diabolical +# mess has been left in the directory thanks to autoconf, automake, and their +# friends. + +if test -f Makefile.plain; then + if test -f Makefile; then + make distclean + fi + mv Makefile.plain Makefile +else + make clean +fi + +rm -f aclocal.m4 config.* configure install-sh \ + missing mkinstalldirs stamp-h.* Makefile.in \ + ltconfig ltmain.sh depcomp +rm -rf autom4te.cache diff --git a/demos/tunala/breakage.c b/demos/tunala/breakage.c new file mode 100644 index 0000000..dcdd64b --- /dev/null +++ b/demos/tunala/breakage.c @@ -0,0 +1,66 @@ +#include "tunala.h" + +int int_strtoul(const char *str, unsigned long *val) +{ +#ifdef HAVE_STRTOUL + char *tmp; + unsigned long ret = strtoul(str, &tmp, 10); + if((str == tmp) || (*tmp != '\0')) + /* The value didn't parse cleanly */ + return 0; + if(ret == ULONG_MAX) + /* We hit a limit */ + return 0; + *val = ret; + return 1; +#else + char buf[2]; + unsigned long ret = 0; + buf[1] = '\0'; + if(str == '\0') + /* An empty string ... */ + return 0; + while(*str != '\0') { + /* We have to multiply 'ret' by 10 before absorbing the next + * digit. If this will overflow, catch it now. */ + if(ret && (((ULONG_MAX + 10) / ret) < 10)) + return 0; + ret *= 10; + if(!isdigit(*str)) + return 0; + buf[0] = *str; + ret += atoi(buf); + str++; + } + *val = ret; + return 1; +#endif +} + +#ifndef HAVE_STRSTR +char *int_strstr(const char *haystack, const char *needle) +{ + const char *sub_haystack = haystack, *sub_needle = needle; + unsigned int offset = 0; + if(!needle) + return haystack; + if(!haystack) + return NULL; + while((*sub_haystack != '\0') && (*sub_needle != '\0')) { + if(sub_haystack[offset] == sub_needle) { + /* sub_haystack is still a candidate */ + offset++; + sub_needle++; + } else { + /* sub_haystack is no longer a possibility */ + sub_haystack++; + offset = 0; + sub_needle = needle; + } + } + if(*sub_haystack == '\0') + /* Found nothing */ + return NULL; + return sub_haystack; +} +#endif diff --git a/demos/tunala/buffer.c b/demos/tunala/buffer.c new file mode 100644 index 0000000..c5cd004 --- /dev/null +++ b/demos/tunala/buffer.c @@ -0,0 +1,205 @@ +#include "tunala.h" + +#ifndef NO_BUFFER + +void buffer_init(buffer_t *buf) +{ + buf->used = 0; + buf->total_in = buf->total_out = 0; +} + +void buffer_close(buffer_t *buf) +{ + /* Our data is static - nothing needs "release", just reset it */ + buf->used = 0; +} + +/* Code these simple ones in compact form */ +unsigned int buffer_used(buffer_t *buf) { + return buf->used; } +unsigned int buffer_unused(buffer_t *buf) { + return (MAX_DATA_SIZE - buf->used); } +int buffer_full(buffer_t *buf) { + return (buf->used == MAX_DATA_SIZE ? 1 : 0); } +int buffer_notfull(buffer_t *buf) { + return (buf->used < MAX_DATA_SIZE ? 1 : 0); } +int buffer_empty(buffer_t *buf) { + return (buf->used == 0 ? 1 : 0); } +int buffer_notempty(buffer_t *buf) { + return (buf->used > 0 ? 1 : 0); } +unsigned long buffer_total_in(buffer_t *buf) { + return buf->total_in; } +unsigned long buffer_total_out(buffer_t *buf) { + return buf->total_out; } + +/* These 3 static (internal) functions don't adjust the "total" variables as + * it's not sure when they're called how it should be interpreted. Only the + * higher-level "buffer_[to|from]_[fd|SSL|BIO]" functions should alter these + * values. */ +#if 0 /* To avoid "unused" warnings */ +static unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr, + unsigned int size) +{ + unsigned int added = MAX_DATA_SIZE - buf->used; + if(added > size) + added = size; + if(added == 0) + return 0; + memcpy(buf->data + buf->used, ptr, added); + buf->used += added; + buf->total_in += added; + return added; +} + +static unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap) +{ + unsigned int moved, tomove = from->used; + if((int)tomove > cap) + tomove = cap; + if(tomove == 0) + return 0; + moved = buffer_adddata(to, from->data, tomove); + if(moved == 0) + return 0; + buffer_takedata(from, NULL, moved); + return moved; +} +#endif + +static unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr, + unsigned int size) +{ + unsigned int taken = buf->used; + if(taken > size) + taken = size; + if(taken == 0) + return 0; + if(ptr) + memcpy(ptr, buf->data, taken); + buf->used -= taken; + /* Do we have to scroll? */ + if(buf->used > 0) + memmove(buf->data, buf->data + taken, buf->used); + return taken; +} + +#ifndef NO_IP + +int buffer_from_fd(buffer_t *buf, int fd) +{ + int toread = buffer_unused(buf); + if(toread == 0) + /* Shouldn't be called in this case! */ + abort(); + toread = read(fd, buf->data + buf->used, toread); + if(toread > 0) { + buf->used += toread; + buf->total_in += toread; + } + return toread; +} + +int buffer_to_fd(buffer_t *buf, int fd) +{ + int towrite = buffer_used(buf); + if(towrite == 0) + /* Shouldn't be called in this case! */ + abort(); + towrite = write(fd, buf->data, towrite); + if(towrite > 0) { + buffer_takedata(buf, NULL, towrite); + buf->total_out += towrite; + } + return towrite; +} + +#endif /* !defined(NO_IP) */ + +#ifndef NO_OPENSSL + +static void int_ssl_check(SSL *s, int ret) +{ + int e = SSL_get_error(s, ret); + switch(e) { + /* These seem to be harmless and already "dealt with" by our + * non-blocking environment. NB: "ZERO_RETURN" is the clean + * "error" indicating a successfully closed SSL tunnel. We let + * this happen because our IO loop should not appear to have + * broken on this condition - and outside the IO loop, the + * "shutdown" state is checked. */ + case SSL_ERROR_NONE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_X509_LOOKUP: + case SSL_ERROR_ZERO_RETURN: + return; + /* These seem to be indications of a genuine error that should + * result in the SSL tunnel being regarded as "dead". */ + case SSL_ERROR_SYSCALL: + case SSL_ERROR_SSL: + SSL_set_app_data(s, (char *)1); + return; + default: + break; + } + /* For any other errors that (a) exist, and (b) crop up - we need to + * interpret what to do with them - so "politely inform" the caller that + * the code needs updating here. */ + abort(); +} + +void buffer_from_SSL(buffer_t *buf, SSL *ssl) +{ + int ret; + if(!ssl || buffer_full(buf)) + return; + ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf)); + if(ret > 0) { + buf->used += ret; + buf->total_in += ret; + } + if(ret < 0) + int_ssl_check(ssl, ret); +} + +void buffer_to_SSL(buffer_t *buf, SSL *ssl) +{ + int ret; + if(!ssl || buffer_empty(buf)) + return; + ret = SSL_write(ssl, buf->data, buf->used); + if(ret > 0) { + buffer_takedata(buf, NULL, ret); + buf->total_out += ret; + } + if(ret < 0) + int_ssl_check(ssl, ret); +} + +void buffer_from_BIO(buffer_t *buf, BIO *bio) +{ + int ret; + if(!bio || buffer_full(buf)) + return; + ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf)); + if(ret > 0) { + buf->used += ret; + buf->total_in += ret; + } +} + +void buffer_to_BIO(buffer_t *buf, BIO *bio) +{ + int ret; + if(!bio || buffer_empty(buf)) + return; + ret = BIO_write(bio, buf->data, buf->used); + if(ret > 0) { + buffer_takedata(buf, NULL, ret); + buf->total_out += ret; + } +} + +#endif /* !defined(NO_OPENSSL) */ + +#endif /* !defined(NO_BUFFER) */ diff --git a/demos/tunala/cb.c b/demos/tunala/cb.c new file mode 100644 index 0000000..f6e452a --- /dev/null +++ b/demos/tunala/cb.c @@ -0,0 +1,162 @@ +#include "tunala.h" + +#ifndef NO_OPENSSL + +/* For callbacks generating output, here are their file-descriptors. */ +static FILE *fp_cb_ssl_info = NULL; +static FILE *fp_cb_ssl_verify = NULL; +/* Output level: + * 0 = nothing, + * 1 = minimal, just errors, + * 2 = minimal, all steps, + * 3 = detail, all steps */ +static unsigned int cb_ssl_verify_level = 1; + +/* Other static rubbish (to mirror s_cb.c where required) */ +static int int_verify_depth = 10; + +/* This function is largely borrowed from the one used in OpenSSL's "s_client" + * and "s_server" utilities. */ +void cb_ssl_info(const SSL *s, int where, int ret) +{ + const char *str1, *str2; + int w; + + if(!fp_cb_ssl_info) + return; + + w = where & ~SSL_ST_MASK; + str1 = (w & SSL_ST_CONNECT ? "SSL_connect" : (w & SSL_ST_ACCEPT ? + "SSL_accept" : "undefined")), + str2 = SSL_state_string_long(s); + + if (where & SSL_CB_LOOP) + fprintf(fp_cb_ssl_info, "(%s) %s\n", str1, str2); + else if (where & SSL_CB_EXIT) { + if (ret == 0) + fprintf(fp_cb_ssl_info, "(%s) failed in %s\n", str1, str2); +/* In a non-blocking model, we get a few of these "error"s simply because we're + * calling "reads" and "writes" on the state-machine that are virtual NOPs + * simply to avoid wasting the time seeing if we *should* call them. Removing + * this case makes the "-out_state" output a lot easier on the eye. */ +#if 0 + else if (ret < 0) + fprintf(fp_cb_ssl_info, "%s:error in %s\n", str1, str2); +#endif + } +} + +void cb_ssl_info_set_output(FILE *fp) +{ + fp_cb_ssl_info = fp; +} + +static const char *int_reason_no_issuer = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"; +static const char *int_reason_not_yet = "X509_V_ERR_CERT_NOT_YET_VALID"; +static const char *int_reason_before = "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"; +static const char *int_reason_expired = "X509_V_ERR_CERT_HAS_EXPIRED"; +static const char *int_reason_after = "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"; + +/* Stolen wholesale from apps/s_cb.c :-) And since then, mutilated ... */ +int cb_ssl_verify(int ok, X509_STORE_CTX *ctx) +{ + char buf1[256]; /* Used for the subject name */ + char buf2[256]; /* Used for the issuer name */ + const char *reason = NULL; /* Error reason (if any) */ + X509 *err_cert; + int err, depth; + + if(!fp_cb_ssl_verify || (cb_ssl_verify_level == 0)) + return ok; + err_cert = X509_STORE_CTX_get_current_cert(ctx); + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + buf1[0] = buf2[0] = '\0'; + /* Fill buf1 */ + X509_NAME_oneline(X509_get_subject_name(err_cert), buf1, 256); + /* Fill buf2 */ + X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf2, 256); + switch (ctx->error) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + reason = int_reason_no_issuer; + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + reason = int_reason_not_yet; + break; + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + reason = int_reason_before; + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + reason = int_reason_expired; + break; + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + reason = int_reason_after; + break; + } + + if((cb_ssl_verify_level == 1) && ok) + return ok; + fprintf(fp_cb_ssl_verify, "chain-depth=%d, ", depth); + if(reason) + fprintf(fp_cb_ssl_verify, "error=%s\n", reason); + else + fprintf(fp_cb_ssl_verify, "error=%d\n", err); + if(cb_ssl_verify_level < 3) + return ok; + fprintf(fp_cb_ssl_verify, "--> subject = %s\n", buf1); + fprintf(fp_cb_ssl_verify, "--> issuer = %s\n", buf2); + if(!ok) + fprintf(fp_cb_ssl_verify,"--> verify error:num=%d:%s\n",err, + X509_verify_cert_error_string(err)); + fprintf(fp_cb_ssl_verify, "--> verify return:%d\n",ok); + return ok; +} + +void cb_ssl_verify_set_output(FILE *fp) +{ + fp_cb_ssl_verify = fp; +} + +void cb_ssl_verify_set_depth(unsigned int verify_depth) +{ + int_verify_depth = verify_depth; +} + +void cb_ssl_verify_set_level(unsigned int level) +{ + if(level < 4) + cb_ssl_verify_level = level; +} + +RSA *cb_generate_tmp_rsa(SSL *s, int is_export, int keylength) +{ + /* TODO: Perhaps make it so our global key can be generated on-the-fly + * after certain intervals? */ + static RSA *rsa_tmp = NULL; + BIGNUM *bn = NULL; + int ok = 1; + if(!rsa_tmp) { + ok = 0; + if(!(bn = BN_new())) + goto end; + if(!BN_set_word(bn, RSA_F4)) + goto end; + if(!(rsa_tmp = RSA_new())) + goto end; + if(!RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL)) + goto end; + ok = 1; + } +end: + if(bn) + BN_free(bn); + if(!ok) { + RSA_free(rsa_tmp); + rsa_tmp = NULL; + } + return rsa_tmp; +} + +#endif /* !defined(NO_OPENSSL) */ + diff --git a/demos/tunala/configure.in b/demos/tunala/configure.in new file mode 100644 index 0000000..590cdbf --- /dev/null +++ b/demos/tunala/configure.in @@ -0,0 +1,29 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(tunala.c) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(tunala, 0.0.1-dev) + +dnl Checks for programs. (Though skip libtool) +AC_PROG_CC +dnl AC_PROG_LIBTOOL +dnl AM_PROG_LIBTOOL + +dnl Checks for libraries. +AC_CHECK_LIB(dl, dlopen) +AC_CHECK_LIB(z, inflate) +AC_CHECK_LIB(socket, socket) +AC_CHECK_LIB(nsl, gethostbyname) + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h limits.h unistd.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +dnl Checks for library functions. +AC_CHECK_FUNCS(strstr strtoul) +AC_CHECK_FUNCS(select socket) +AC_CHECK_FUNCS(dlopen) + +AC_OUTPUT(Makefile) diff --git a/demos/tunala/ip.c b/demos/tunala/ip.c new file mode 100644 index 0000000..96ef4e6 --- /dev/null +++ b/demos/tunala/ip.c @@ -0,0 +1,146 @@ +#include "tunala.h" + +#ifndef NO_IP + +#define IP_LISTENER_BACKLOG 511 /* So if it gets masked by 256 or some other + such value it'll still be respectable */ + +/* Any IP-related initialisations. For now, this means blocking SIGPIPE */ +int ip_initialise(void) +{ + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + if(sigaction(SIGPIPE, &sa, NULL) != 0) + return 0; + return 1; +} + +int ip_create_listener_split(const char *ip, unsigned short port) +{ + struct sockaddr_in in_addr; + int fd = -1; + int reuseVal = 1; + + /* Create the socket */ + if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) + goto err; + /* Set the SO_REUSEADDR flag - servers act weird without it */ + if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal), + sizeof(reuseVal)) != 0) + goto err; + /* Prepare the listen address stuff */ + in_addr.sin_family = AF_INET; + memcpy(&in_addr.sin_addr.s_addr, ip, 4); + in_addr.sin_port = htons(port); + /* Bind to the required port/address/interface */ + if(bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) != 0) + goto err; + /* Start "listening" */ + if(listen(fd, IP_LISTENER_BACKLOG) != 0) + goto err; + return fd; +err: + if(fd != -1) + close(fd); + return -1; +} + +int ip_create_connection_split(const char *ip, unsigned short port) +{ + struct sockaddr_in in_addr; + int flags, fd = -1; + + /* Create the socket */ + if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) + goto err; + /* Make it non-blocking */ + if(((flags = fcntl(fd, F_GETFL, 0)) < 0) || + (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)) + goto err; + /* Prepare the connection address stuff */ + in_addr.sin_family = AF_INET; + memcpy(&in_addr.sin_addr.s_addr, ip, 4); + in_addr.sin_port = htons(port); + /* Start a connect (non-blocking, in all likelihood) */ + if((connect(fd, (struct sockaddr *)&in_addr, + sizeof(struct sockaddr_in)) != 0) && + (errno != EINPROGRESS)) + goto err; + return fd; +err: + if(fd != -1) + close(fd); + return -1; +} + +static char all_local_ip[] = {0x00,0x00,0x00,0x00}; + +int ip_parse_address(const char *address, const char **parsed_ip, + unsigned short *parsed_port, int accept_all_ip) +{ + char buf[256]; + struct hostent *lookup; + unsigned long port; + const char *ptr = strstr(address, ":"); + const char *ip = all_local_ip; + + if(!ptr) { + /* We assume we're listening on all local interfaces and have + * only specified a port. */ + if(!accept_all_ip) + return 0; + ptr = address; + goto determine_port; + } + if((ptr - address) > 255) + return 0; + memset(buf, 0, 256); + memcpy(buf, address, ptr - address); + ptr++; + if((lookup = gethostbyname(buf)) == NULL) { + /* Spit a message to differentiate between lookup failures and + * bad strings. */ + fprintf(stderr, "hostname lookup for '%s' failed\n", buf); + return 0; + } + ip = lookup->h_addr_list[0]; +determine_port: + if(strlen(ptr) < 1) + return 0; + if(!int_strtoul(ptr, &port) || (port > 65535)) + return 0; + *parsed_ip = ip; + *parsed_port = (unsigned short)port; + return 1; +} + +int ip_create_listener(const char *address) +{ + const char *ip; + unsigned short port; + + if(!ip_parse_address(address, &ip, &port, 1)) + return -1; + return ip_create_listener_split(ip, port); +} + +int ip_create_connection(const char *address) +{ + const char *ip; + unsigned short port; + + if(!ip_parse_address(address, &ip, &port, 0)) + return -1; + return ip_create_connection_split(ip, port); +} + +int ip_accept_connection(int listen_fd) +{ + return accept(listen_fd, NULL, NULL); +} + +#endif /* !defined(NO_IP) */ + diff --git a/demos/tunala/sm.c b/demos/tunala/sm.c new file mode 100644 index 0000000..25359e6 --- /dev/null +++ b/demos/tunala/sm.c @@ -0,0 +1,151 @@ +#include "tunala.h" + +#ifndef NO_TUNALA + +void state_machine_init(state_machine_t *machine) +{ + machine->ssl = NULL; + machine->bio_intossl = machine->bio_fromssl = NULL; + buffer_init(&machine->clean_in); + buffer_init(&machine->clean_out); + buffer_init(&machine->dirty_in); + buffer_init(&machine->dirty_out); +} + +void state_machine_close(state_machine_t *machine) +{ + if(machine->ssl) + SSL_free(machine->ssl); +/* SSL_free seems to decrement the reference counts already so doing this goes + * kaboom. */ +#if 0 + if(machine->bio_intossl) + BIO_free(machine->bio_intossl); + if(machine->bio_fromssl) + BIO_free(machine->bio_fromssl); +#endif + buffer_close(&machine->clean_in); + buffer_close(&machine->clean_out); + buffer_close(&machine->dirty_in); + buffer_close(&machine->dirty_out); + state_machine_init(machine); +} + +buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type) +{ + switch(type) { + case SM_CLEAN_IN: + return &machine->clean_in; + case SM_CLEAN_OUT: + return &machine->clean_out; + case SM_DIRTY_IN: + return &machine->dirty_in; + case SM_DIRTY_OUT: + return &machine->dirty_out; + default: + break; + } + /* Should never get here */ + abort(); + return NULL; +} + +SSL *state_machine_get_SSL(state_machine_t *machine) +{ + return machine->ssl; +} + +int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server) +{ + if(machine->ssl) + /* Shouldn't ever be set twice */ + abort(); + machine->ssl = ssl; + /* Create the BIOs to handle the dirty side of the SSL */ + if((machine->bio_intossl = BIO_new(BIO_s_mem())) == NULL) + abort(); + if((machine->bio_fromssl = BIO_new(BIO_s_mem())) == NULL) + abort(); + /* Hook up the BIOs on the dirty side of the SSL */ + SSL_set_bio(machine->ssl, machine->bio_intossl, machine->bio_fromssl); + if(is_server) + SSL_set_accept_state(machine->ssl); + else + SSL_set_connect_state(machine->ssl); + /* If we're the first one to generate traffic - do it now otherwise we + * go into the next select empty-handed and our peer will not send data + * but will similarly wait for us. */ + return state_machine_churn(machine); +} + +/* Performs the data-IO loop and returns zero if the machine should close */ +int state_machine_churn(state_machine_t *machine) +{ + unsigned int loop; + if(machine->ssl == NULL) { + if(buffer_empty(&machine->clean_out)) + /* Time to close this state-machine altogether */ + return 0; + else + /* Still buffered data on the clean side to go out */ + return 1; + } + /* Do this loop twice to cover any dependencies about which precise + * order of reads and writes is required. */ + for(loop = 0; loop < 2; loop++) { + buffer_to_SSL(&machine->clean_in, machine->ssl); + buffer_to_BIO(&machine->dirty_in, machine->bio_intossl); + buffer_from_SSL(&machine->clean_out, machine->ssl); + buffer_from_BIO(&machine->dirty_out, machine->bio_fromssl); + } + /* We close on the SSL side if the info callback noticed some problems + * or an SSL shutdown was underway and shutdown traffic had all been + * sent. */ + if(SSL_get_app_data(machine->ssl) || (SSL_get_shutdown(machine->ssl) && + buffer_empty(&machine->dirty_out))) { + /* Great, we can seal off the dirty side completely */ + if(!state_machine_close_dirty(machine)) + return 0; + } + /* Either the SSL is alive and well, or the closing process still has + * outgoing data waiting to be sent */ + return 1; +} + +/* Called when the clean side of the SSL has lost its connection */ +int state_machine_close_clean(state_machine_t *machine) +{ + /* Well, first thing to do is null out the clean-side buffers - they're + * no use any more. */ + buffer_close(&machine->clean_in); + buffer_close(&machine->clean_out); + /* And start an SSL shutdown */ + if(machine->ssl) + SSL_shutdown(machine->ssl); + /* This is an "event", so flush the SSL of any generated traffic */ + state_machine_churn(machine); + if(buffer_empty(&machine->dirty_in) && + buffer_empty(&machine->dirty_out)) + return 0; + return 1; +} + +/* Called when the dirty side of the SSL has lost its connection. This is pretty + * terminal as all that can be left to do is send any buffered output on the + * clean side - after that, we're done. */ +int state_machine_close_dirty(state_machine_t *machine) +{ + buffer_close(&machine->dirty_in); + buffer_close(&machine->dirty_out); + buffer_close(&machine->clean_in); + if(machine->ssl) + SSL_free(machine->ssl); + machine->ssl = NULL; + machine->bio_intossl = machine->bio_fromssl = NULL; + if(buffer_empty(&machine->clean_out)) + return 0; + return 1; +} + +#endif /* !defined(NO_TUNALA) */ + diff --git a/demos/tunala/test.sh b/demos/tunala/test.sh new file mode 100755 index 0000000..105b447 --- /dev/null +++ b/demos/tunala/test.sh @@ -0,0 +1,107 @@ +#!/bin/sh + +HTTP="localhost:8080" +CLIENT_PORT="9020" +SERVER_PORT="9021" + +sub_test () +{ + echo "STARTING - $VER $CIPHER" + ./tunala -listen localhost:$CLIENT_PORT -proxy localhost:$SERVER_PORT \ + -cacert CA.pem -cert A-client.pem -server 0 \ + -dh_special standard -v_peer -v_strict \ + $VER -cipher $CIPHER 1> tc1.txt 2> tc2.txt & + ./tunala -listen localhost:$SERVER_PORT -proxy $HTTP \ + -cacert CA.pem -cert A-server.pem -server 1 \ + -dh_special standard -v_peer -v_strict \ + $VER -cipher $CIPHER 1> ts1.txt 2> ts2.txt & + # Wait for the servers to be listening before starting the wget test + DONE="no" + while [ "$DONE" != "yes" ]; do + L1=`netstat -a | egrep "LISTEN[\t ]*$" | grep ":$CLIENT_PORT"` + L2=`netstat -a | egrep "LISTEN[\t ]*$" | grep ":$SERVER_PORT"` + if [ "x$L1" != "x" ]; then + DONE="yes" + elif [ "x$L2" != "x" ]; then + DONE="yes" + else + sleep 1 + fi + done + HTML=`wget -O - -T 1 http://localhost:$CLIENT_PORT 2> /dev/null | grep ""` + if [ "x$HTML" != "x" ]; then + echo "OK - $CIPHER ($VER)" + else + echo "FAIL - $CIPHER ($VER)" + killall tunala + exit 1 + fi + killall tunala + # Wait for the servers to stop before returning - otherwise the next + # test my fail to start ... (fscking race conditions) + DONE="yes" + while [ "$DONE" != "no" ]; do + L1=`netstat -a | egrep "LISTEN[\t ]*$" | grep ":$CLIENT_PORT"` + L2=`netstat -a | egrep "LISTEN[\t ]*$" | grep ":$SERVER_PORT"` + if [ "x$L1" != "x" ]; then + DONE="yes" + elif [ "x$L2" != "x" ]; then + DONE="yes" + else + DONE="no" + fi + done + exit 0 +} + +run_test () +{ + (sub_test 1> /dev/null) || exit 1 +} + +run_ssl_test () +{ +killall tunala 1> /dev/null 2> /dev/null +echo "" +echo "Starting all $PRETTY tests" +if [ "$PRETTY" != "SSLv2" ]; then + if [ "$PRETTY" != "SSLv3" ]; then + export VER="-no_ssl2 -no_ssl3" + export OSSL="-tls1" + else + export VER="-no_ssl2 -no_tls1" + export OSSL="-ssl3" + fi +else + export VER="-no_ssl3 -no_tls1" + export OSSL="-ssl2" +fi +LIST="`../../apps/openssl ciphers $OSSL | sed -e 's/:/ /g'`" +#echo "$LIST" +for i in $LIST; do \ + DSS=`echo "$i" | grep "DSS"` + if [ "x$DSS" != "x" ]; then + echo "---- skipping $i (no DSA cert/keys) ----" + else + export CIPHER=$i + run_test + echo "SUCCESS: $i" + fi +done; +} + +# Welcome the user +echo "Tests will assume an http server running at $HTTP" + +# TLSv1 test +export PRETTY="TLSv1" +run_ssl_test + +# SSLv3 test +export PRETTY="SSLv3" +run_ssl_test + +# SSLv2 test +export PRETTY="SSLv2" +run_ssl_test + diff --git a/demos/tunala/tunala.c b/demos/tunala/tunala.c new file mode 100644 index 0000000..ec49d3e --- /dev/null +++ b/demos/tunala/tunala.c @@ -0,0 +1,1109 @@ +#if defined(NO_BUFFER) || defined(NO_IP) || defined(NO_OPENSSL) +#error "Badness, NO_BUFFER, NO_IP or NO_OPENSSL is defined, turn them *off*" +#endif + +/* Include our bits'n'pieces */ +#include "tunala.h" + + +/********************************************/ +/* Our local types that specify our "world" */ +/********************************************/ + +/* These represent running "tunnels". Eg. if you wanted to do SSL in a + * "message-passing" scanario, the "int" file-descriptors might be replaced by + * thread or process IDs, and the "select" code might be replaced by message + * handling code. Whatever. */ +typedef struct _tunala_item_t { + /* The underlying SSL state machine. This is a data-only processing unit + * and we communicate with it by talking to its four "buffers". */ + state_machine_t sm; + /* The file-descriptors for the "dirty" (encrypted) side of the SSL + * setup. In actuality, this is typically a socket and both values are + * identical. */ + int dirty_read, dirty_send; + /* The file-descriptors for the "clean" (unencrypted) side of the SSL + * setup. These could be stdin/stdout, a socket (both values the same), + * or whatever you like. */ + int clean_read, clean_send; +} tunala_item_t; + +/* This structure is used as the data for running the main loop. Namely, in a + * network format such as this, it is stuff for select() - but as pointed out, + * when moving the real-world to somewhere else, this might be replaced by + * something entirely different. It's basically the stuff that controls when + * it's time to do some "work". */ +typedef struct _select_sets_t { + int max; /* As required as the first argument to select() */ + fd_set reads, sends, excepts; /* As passed to select() */ +} select_sets_t; +typedef struct _tunala_selector_t { + select_sets_t last_selected; /* Results of the last select() */ + select_sets_t next_select; /* What we'll next select on */ +} tunala_selector_t; + +/* This structure is *everything*. We do it to avoid the use of globals so that, + * for example, it would be easier to shift things around between async-IO, + * thread-based, or multi-fork()ed (or combinations thereof). */ +typedef struct _tunala_world_t { + /* The file-descriptor we "listen" on for new connections */ + int listen_fd; + /* The array of tunnels */ + tunala_item_t *tunnels; + /* the number of tunnels in use and allocated, respectively */ + unsigned int tunnels_used, tunnels_size; + /* Our outside "loop" context stuff */ + tunala_selector_t selector; + /* Our SSL_CTX, which is configured as the SSL client or server and has + * the various cert-settings and callbacks configured. */ + SSL_CTX *ssl_ctx; + /* Simple flag with complex logic :-) Indicates whether we're an SSL + * server or an SSL client. */ + int server_mode; +} tunala_world_t; + +/*****************************/ +/* Internal static functions */ +/*****************************/ + +static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, + const char *CAfile, const char *cert, const char *key, + const char *dcert, const char *dkey, const char *cipher_list, + const char *dh_file, const char *dh_special, int tmp_rsa, + int ctx_options, int out_state, int out_verify, int verify_mode, + unsigned int verify_depth); +static void selector_init(tunala_selector_t *selector); +static void selector_add_listener(tunala_selector_t *selector, int fd); +static void selector_add_tunala(tunala_selector_t *selector, tunala_item_t *t); +static int selector_select(tunala_selector_t *selector); +/* This returns -1 for error, 0 for no new connections, or 1 for success, in + * which case *newfd is populated. */ +static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd); +static int tunala_world_new_item(tunala_world_t *world, int fd, + const char *ip, unsigned short port, int flipped); +static void tunala_world_del_item(tunala_world_t *world, unsigned int idx); +static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item); + +/*********************************************/ +/* MAIN FUNCTION (and its utility functions) */ +/*********************************************/ + +static const char *def_proxyhost = "127.0.0.1:443"; +static const char *def_listenhost = "127.0.0.1:8080"; +static int def_max_tunnels = 50; +static const char *def_cacert = NULL; +static const char *def_cert = NULL; +static const char *def_key = NULL; +static const char *def_dcert = NULL; +static const char *def_dkey = NULL; +static const char *def_engine_id = NULL; +static int def_server_mode = 0; +static int def_flipped = 0; +static const char *def_cipher_list = NULL; +static const char *def_dh_file = NULL; +static const char *def_dh_special = NULL; +static int def_tmp_rsa = 1; +static int def_ctx_options = 0; +static int def_verify_mode = 0; +static unsigned int def_verify_depth = 10; +static int def_out_state = 0; +static unsigned int def_out_verify = 0; +static int def_out_totals = 0; +static int def_out_conns = 0; + +static const char *helpstring = +"\n'Tunala' (A tunneler with a New Zealand accent)\n" +"Usage: tunala [options], where options are from;\n" +" -listen [host:] (default = 127.0.0.1:8080)\n" +" -proxy : (default = 127.0.0.1:443)\n" +" -maxtunnels (default = 50)\n" +" -cacert (default = NULL)\n" +" -cert (default = NULL)\n" +" -key (default = whatever '-cert' is)\n" +" -dcert (usually for DSA, default = NULL)\n" +" -dkey (usually for DSA, default = whatever '-dcert' is)\n" +" -engine (default = NULL)\n" +" -server <0|1> (default = 0, ie. an SSL client)\n" +" -flipped <0|1> (makes SSL servers be network clients, and vice versa)\n" +" -cipher (specifies cipher list to use)\n" +" -dh_file (a PEM file containing DH parameters to use)\n" +" -dh_special (see below: def=NULL)\n" +" -no_tmp_rsa (don't generate temporary RSA keys)\n" +" -no_ssl2 (disable SSLv2)\n" +" -no_ssl3 (disable SSLv3)\n" +" -no_tls1 (disable TLSv1)\n" +" -v_peer (verify the peer certificate)\n" +" -v_strict (do not continue if peer doesn't authenticate)\n" +" -v_once (no verification in renegotiates)\n" +" -v_depth (limit certificate chain depth, default = 10)\n" +" -out_conns (prints client connections and disconnections)\n" +" -out_state (prints SSL handshake states)\n" +" -out_verify <0|1|2|3> (prints certificate verification states: def=1)\n" +" -out_totals (prints out byte-totals when a tunnel closes)\n" +" - (displays this help screen)\n" +"Notes:\n" +"(1) It is recommended to specify a cert+key when operating as an SSL server.\n" +" If you only specify '-cert', the same file must contain a matching\n" +" private key.\n" +"(2) Either dh_file or dh_special can be used to specify where DH parameters\n" +" will be obtained from (or '-dh_special NULL' for the default choice) but\n" +" you cannot specify both. For dh_special, 'generate' will create new DH\n" +" parameters on startup, and 'standard' will use embedded parameters\n" +" instead.\n" +"(3) Normally an ssl client connects to an ssl server - so that an 'ssl client\n" +" tunala' listens for 'clean' client connections and proxies ssl, and an\n" +" 'ssl server tunala' listens for ssl connections and proxies 'clean'. With\n" +" '-flipped 1', this behaviour is reversed so that an 'ssl server tunala'\n" +" listens for clean client connections and proxies ssl (but participating\n" +" as an ssl *server* in the SSL/TLS protocol), and an 'ssl client tunala'\n" +" listens for ssl connections (participating as an ssl *client* in the\n" +" SSL/TLS protocol) and proxies 'clean' to the end destination. This can\n" +" be useful for allowing network access to 'servers' where only the server\n" +" needs to authenticate the client (ie. the other way is not required).\n" +" Even with client and server authentication, this 'technique' mitigates\n" +" some DoS (denial-of-service) potential as it will be the network client\n" +" having to perform the first private key operation rather than the other\n" +" way round.\n" +"(4) The 'technique' used by setting '-flipped 1' is probably compatible with\n" +" absolutely nothing except another complimentary instance of 'tunala'\n" +" running with '-flipped 1'. :-)\n"; + +/* Default DH parameters for use with "-dh_special standard" ... stolen striaght + * from s_server. */ +static unsigned char dh512_p[]={ + 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75, + 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F, + 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3, + 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12, + 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C, + 0x47,0x74,0xE8,0x33, + }; +static unsigned char dh512_g[]={ + 0x02, + }; + +/* And the function that parses the above "standard" parameters, again, straight + * out of s_server. */ +static DH *get_dh512(void) + { + DH *dh=NULL; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL); + dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + return(NULL); + return(dh); + } + +/* Various help/error messages used by main() */ +static int usage(const char *errstr, int isunknownarg) +{ + if(isunknownarg) + fprintf(stderr, "Error: unknown argument '%s'\n", errstr); + else + fprintf(stderr, "Error: %s\n", errstr); + fprintf(stderr, "%s\n", helpstring); + return 1; +} + +static int err_str0(const char *str0) +{ + fprintf(stderr, "%s\n", str0); + return 1; +} + +static int err_str1(const char *fmt, const char *str1) +{ + fprintf(stderr, fmt, str1); + fprintf(stderr, "\n"); + return 1; +} + +static int parse_max_tunnels(const char *s, unsigned int *maxtunnels) +{ + unsigned long l; + if(!int_strtoul(s, &l) || (l < 1) || (l > 1024)) { + fprintf(stderr, "Error, '%s' is an invalid value for " + "maxtunnels\n", s); + return 0; + } + *maxtunnels = (unsigned int)l; + return 1; +} + +static int parse_server_mode(const char *s, int *servermode) +{ + unsigned long l; + if(!int_strtoul(s, &l) || (l > 1)) { + fprintf(stderr, "Error, '%s' is an invalid value for the " + "server mode\n", s); + return 0; + } + *servermode = (int)l; + return 1; +} + +static int parse_dh_special(const char *s, const char **dh_special) +{ + if((strcmp(s, "NULL") == 0) || (strcmp(s, "generate") == 0) || + (strcmp(s, "standard") == 0)) { + *dh_special = s; + return 1; + } + fprintf(stderr, "Error, '%s' is an invalid value for 'dh_special'\n", s); + return 0; +} + +static int parse_verify_level(const char *s, unsigned int *verify_level) +{ + unsigned long l; + if(!int_strtoul(s, &l) || (l > 3)) { + fprintf(stderr, "Error, '%s' is an invalid value for " + "out_verify\n", s); + return 0; + } + *verify_level = (unsigned int)l; + return 1; +} + +static int parse_verify_depth(const char *s, unsigned int *verify_depth) +{ + unsigned long l; + if(!int_strtoul(s, &l) || (l < 1) || (l > 50)) { + fprintf(stderr, "Error, '%s' is an invalid value for " + "verify_depth\n", s); + return 0; + } + *verify_depth = (unsigned int)l; + return 1; +} + +/* Some fprintf format strings used when tunnels close */ +static const char *io_stats_dirty = +" SSL traffic; %8lu bytes in, %8lu bytes out\n"; +static const char *io_stats_clean = +" clear traffic; %8lu bytes in, %8lu bytes out\n"; + +int main(int argc, char *argv[]) +{ + unsigned int loop; + int newfd; + tunala_world_t world; + tunala_item_t *t_item; + const char *proxy_ip; + unsigned short proxy_port; + /* Overridables */ + const char *proxyhost = def_proxyhost; + const char *listenhost = def_listenhost; + unsigned int max_tunnels = def_max_tunnels; + const char *cacert = def_cacert; + const char *cert = def_cert; + const char *key = def_key; + const char *dcert = def_dcert; + const char *dkey = def_dkey; + const char *engine_id = def_engine_id; + int server_mode = def_server_mode; + int flipped = def_flipped; + const char *cipher_list = def_cipher_list; + const char *dh_file = def_dh_file; + const char *dh_special = def_dh_special; + int tmp_rsa = def_tmp_rsa; + int ctx_options = def_ctx_options; + int verify_mode = def_verify_mode; + unsigned int verify_depth = def_verify_depth; + int out_state = def_out_state; + unsigned int out_verify = def_out_verify; + int out_totals = def_out_totals; + int out_conns = def_out_conns; + +/* Parse command-line arguments */ +next_arg: + argc--; argv++; + if(argc > 0) { + if(strcmp(*argv, "-listen") == 0) { + if(argc < 2) + return usage("-listen requires an argument", 0); + argc--; argv++; + listenhost = *argv; + goto next_arg; + } else if(strcmp(*argv, "-proxy") == 0) { + if(argc < 2) + return usage("-proxy requires an argument", 0); + argc--; argv++; + proxyhost = *argv; + goto next_arg; + } else if(strcmp(*argv, "-maxtunnels") == 0) { + if(argc < 2) + return usage("-maxtunnels requires an argument", 0); + argc--; argv++; + if(!parse_max_tunnels(*argv, &max_tunnels)) + return 1; + goto next_arg; + } else if(strcmp(*argv, "-cacert") == 0) { + if(argc < 2) + return usage("-cacert requires an argument", 0); + argc--; argv++; + if(strcmp(*argv, "NULL") == 0) + cacert = NULL; + else + cacert = *argv; + goto next_arg; + } else if(strcmp(*argv, "-cert") == 0) { + if(argc < 2) + return usage("-cert requires an argument", 0); + argc--; argv++; + if(strcmp(*argv, "NULL") == 0) + cert = NULL; + else + cert = *argv; + goto next_arg; + } else if(strcmp(*argv, "-key") == 0) { + if(argc < 2) + return usage("-key requires an argument", 0); + argc--; argv++; + if(strcmp(*argv, "NULL") == 0) + key = NULL; + else + key = *argv; + goto next_arg; + } else if(strcmp(*argv, "-dcert") == 0) { + if(argc < 2) + return usage("-dcert requires an argument", 0); + argc--; argv++; + if(strcmp(*argv, "NULL") == 0) + dcert = NULL; + else + dcert = *argv; + goto next_arg; + } else if(strcmp(*argv, "-dkey") == 0) { + if(argc < 2) + return usage("-dkey requires an argument", 0); + argc--; argv++; + if(strcmp(*argv, "NULL") == 0) + dkey = NULL; + else + dkey = *argv; + goto next_arg; + } else if(strcmp(*argv, "-engine") == 0) { + if(argc < 2) + return usage("-engine requires an argument", 0); + argc--; argv++; + engine_id = *argv; + goto next_arg; + } else if(strcmp(*argv, "-server") == 0) { + if(argc < 2) + return usage("-server requires an argument", 0); + argc--; argv++; + if(!parse_server_mode(*argv, &server_mode)) + return 1; + goto next_arg; + } else if(strcmp(*argv, "-flipped") == 0) { + if(argc < 2) + return usage("-flipped requires an argument", 0); + argc--; argv++; + if(!parse_server_mode(*argv, &flipped)) + return 1; + goto next_arg; + } else if(strcmp(*argv, "-cipher") == 0) { + if(argc < 2) + return usage("-cipher requires an argument", 0); + argc--; argv++; + cipher_list = *argv; + goto next_arg; + } else if(strcmp(*argv, "-dh_file") == 0) { + if(argc < 2) + return usage("-dh_file requires an argument", 0); + if(dh_special) + return usage("cannot mix -dh_file with " + "-dh_special", 0); + argc--; argv++; + dh_file = *argv; + goto next_arg; + } else if(strcmp(*argv, "-dh_special") == 0) { + if(argc < 2) + return usage("-dh_special requires an argument", 0); + if(dh_file) + return usage("cannot mix -dh_file with " + "-dh_special", 0); + argc--; argv++; + if(!parse_dh_special(*argv, &dh_special)) + return 1; + goto next_arg; + } else if(strcmp(*argv, "-no_tmp_rsa") == 0) { + tmp_rsa = 0; + goto next_arg; + } else if(strcmp(*argv, "-no_ssl2") == 0) { + ctx_options |= SSL_OP_NO_SSLv2; + goto next_arg; + } else if(strcmp(*argv, "-no_ssl3") == 0) { + ctx_options |= SSL_OP_NO_SSLv3; + goto next_arg; + } else if(strcmp(*argv, "-no_tls1") == 0) { + ctx_options |= SSL_OP_NO_TLSv1; + goto next_arg; + } else if(strcmp(*argv, "-v_peer") == 0) { + verify_mode |= SSL_VERIFY_PEER; + goto next_arg; + } else if(strcmp(*argv, "-v_strict") == 0) { + verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + goto next_arg; + } else if(strcmp(*argv, "-v_once") == 0) { + verify_mode |= SSL_VERIFY_CLIENT_ONCE; + goto next_arg; + } else if(strcmp(*argv, "-v_depth") == 0) { + if(argc < 2) + return usage("-v_depth requires an argument", 0); + argc--; argv++; + if(!parse_verify_depth(*argv, &verify_depth)) + return 1; + goto next_arg; + } else if(strcmp(*argv, "-out_state") == 0) { + out_state = 1; + goto next_arg; + } else if(strcmp(*argv, "-out_verify") == 0) { + if(argc < 2) + return usage("-out_verify requires an argument", 0); + argc--; argv++; + if(!parse_verify_level(*argv, &out_verify)) + return 1; + goto next_arg; + } else if(strcmp(*argv, "-out_totals") == 0) { + out_totals = 1; + goto next_arg; + } else if(strcmp(*argv, "-out_conns") == 0) { + out_conns = 1; + goto next_arg; + } else if((strcmp(*argv, "-h") == 0) || + (strcmp(*argv, "-help") == 0) || + (strcmp(*argv, "-?") == 0)) { + fprintf(stderr, "%s\n", helpstring); + return 0; + } else + return usage(*argv, 1); + } + /* Run any sanity checks we want here */ + if(!cert && !dcert && server_mode) + fprintf(stderr, "WARNING: you are running an SSL server without " + "a certificate - this may not work!\n"); + + /* Initialise network stuff */ + if(!ip_initialise()) + return err_str0("ip_initialise failed"); + /* Create the SSL_CTX */ + if((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id, + cacert, cert, key, dcert, dkey, cipher_list, dh_file, + dh_special, tmp_rsa, ctx_options, out_state, out_verify, + verify_mode, verify_depth)) == NULL) + return err_str1("initialise_ssl_ctx(engine_id=%s) failed", + (engine_id == NULL) ? "NULL" : engine_id); + if(engine_id) + fprintf(stderr, "Info, engine '%s' initialised\n", engine_id); + /* Create the listener */ + if((world.listen_fd = ip_create_listener(listenhost)) == -1) + return err_str1("ip_create_listener(%s) failed", listenhost); + fprintf(stderr, "Info, listening on '%s'\n", listenhost); + if(!ip_parse_address(proxyhost, &proxy_ip, &proxy_port, 0)) + return err_str1("ip_parse_address(%s) failed", proxyhost); + fprintf(stderr, "Info, proxying to '%s' (%d.%d.%d.%d:%d)\n", proxyhost, + (int)proxy_ip[0], (int)proxy_ip[1], + (int)proxy_ip[2], (int)proxy_ip[3], (int)proxy_port); + fprintf(stderr, "Info, set maxtunnels to %d\n", (int)max_tunnels); + fprintf(stderr, "Info, set to operate as an SSL %s\n", + (server_mode ? "server" : "client")); + /* Initialise the rest of the stuff */ + world.tunnels_used = world.tunnels_size = 0; + world.tunnels = NULL; + world.server_mode = server_mode; + selector_init(&world.selector); + +/* We're ready to loop */ +main_loop: + /* Should we listen for *new* tunnels? */ + if(world.tunnels_used < max_tunnels) + selector_add_listener(&world.selector, world.listen_fd); + /* We should add in our existing tunnels */ + for(loop = 0; loop < world.tunnels_used; loop++) + selector_add_tunala(&world.selector, world.tunnels + loop); + /* Now do the select */ + switch(selector_select(&world.selector)) { + case -1: + if(errno != EINTR) { + fprintf(stderr, "selector_select returned a " + "badness error.\n"); + goto shouldnt_happen; + } + fprintf(stderr, "Warn, selector interrupted by a signal\n"); + goto main_loop; + case 0: + fprintf(stderr, "Warn, selector_select returned 0 - signal?""?\n"); + goto main_loop; + default: + break; + } + /* Accept new connection if we should and can */ + if((world.tunnels_used < max_tunnels) && (selector_get_listener( + &world.selector, world.listen_fd, + &newfd) == 1)) { + /* We have a new connection */ + if(!tunala_world_new_item(&world, newfd, proxy_ip, + proxy_port, flipped)) + fprintf(stderr, "tunala_world_new_item failed\n"); + else if(out_conns) + fprintf(stderr, "Info, new tunnel opened, now up to " + "%d\n", world.tunnels_used); + } + /* Give each tunnel its moment, note the while loop is because it makes + * the logic easier than with "for" to deal with an array that may shift + * because of deletes. */ + loop = 0; + t_item = world.tunnels; + while(loop < world.tunnels_used) { + if(!tunala_item_io(&world.selector, t_item)) { + /* We're closing whether for reasons of an error or a + * natural close. Don't increment loop or t_item because + * the next item is moving to us! */ + if(!out_totals) + goto skip_totals; + fprintf(stderr, "Tunnel closing, traffic stats follow\n"); + /* Display the encrypted (over the network) stats */ + fprintf(stderr, io_stats_dirty, + buffer_total_in(state_machine_get_buffer( + &t_item->sm,SM_DIRTY_IN)), + buffer_total_out(state_machine_get_buffer( + &t_item->sm,SM_DIRTY_OUT))); + /* Display the local (tunnelled) stats. NB: Data we + * *receive* is data sent *out* of the state_machine on + * its 'clean' side. Hence the apparent back-to-front + * OUT/IN mixup here :-) */ + fprintf(stderr, io_stats_clean, + buffer_total_out(state_machine_get_buffer( + &t_item->sm,SM_CLEAN_OUT)), + buffer_total_in(state_machine_get_buffer( + &t_item->sm,SM_CLEAN_IN))); +skip_totals: + tunala_world_del_item(&world, loop); + if(out_conns) + fprintf(stderr, "Info, tunnel closed, down to %d\n", + world.tunnels_used); + } + else { + /* Move to the next item */ + loop++; + t_item++; + } + } + goto main_loop; + /* Should never get here */ +shouldnt_happen: + abort(); + return 1; +} + +/****************/ +/* OpenSSL bits */ +/****************/ + +static int ctx_set_cert(SSL_CTX *ctx, const char *cert, const char *key) +{ + FILE *fp = NULL; + X509 *x509 = NULL; + EVP_PKEY *pkey = NULL; + int toret = 0; /* Assume an error */ + + /* cert */ + if(cert) { + if((fp = fopen(cert, "r")) == NULL) { + fprintf(stderr, "Error opening cert file '%s'\n", cert); + goto err; + } + if(!PEM_read_X509(fp, &x509, NULL, NULL)) { + fprintf(stderr, "Error reading PEM cert from '%s'\n", + cert); + goto err; + } + if(!SSL_CTX_use_certificate(ctx, x509)) { + fprintf(stderr, "Error, cert in '%s' can not be used\n", + cert); + goto err; + } + /* Clear the FILE* for reuse in the "key" code */ + fclose(fp); + fp = NULL; + fprintf(stderr, "Info, operating with cert in '%s'\n", cert); + /* If a cert was given without matching key, we assume the same + * file contains the required key. */ + if(!key) + key = cert; + } else { + if(key) + fprintf(stderr, "Error, can't specify a key without a " + "corresponding certificate\n"); + else + fprintf(stderr, "Error, ctx_set_cert called with " + "NULLs!\n"); + goto err; + } + /* key */ + if(key) { + if((fp = fopen(key, "r")) == NULL) { + fprintf(stderr, "Error opening key file '%s'\n", key); + goto err; + } + if(!PEM_read_PrivateKey(fp, &pkey, NULL, NULL)) { + fprintf(stderr, "Error reading PEM key from '%s'\n", + key); + goto err; + } + if(!SSL_CTX_use_PrivateKey(ctx, pkey)) { + fprintf(stderr, "Error, key in '%s' can not be used\n", + key); + goto err; + } + fprintf(stderr, "Info, operating with key in '%s'\n", key); + } else + fprintf(stderr, "Info, operating without a cert or key\n"); + /* Success */ + toret = 1; err: + if(x509) + X509_free(x509); + if(pkey) + EVP_PKEY_free(pkey); + if(fp) + fclose(fp); + return toret; +} + +static int ctx_set_dh(SSL_CTX *ctx, const char *dh_file, const char *dh_special) +{ + DH *dh = NULL; + FILE *fp = NULL; + + if(dh_special) { + if(strcmp(dh_special, "NULL") == 0) + return 1; + if(strcmp(dh_special, "standard") == 0) { + if((dh = get_dh512()) == NULL) { + fprintf(stderr, "Error, can't parse 'standard'" + " DH parameters\n"); + return 0; + } + fprintf(stderr, "Info, using 'standard' DH parameters\n"); + goto do_it; + } + if(strcmp(dh_special, "generate") != 0) + /* This shouldn't happen - screening values is handled + * in main(). */ + abort(); + fprintf(stderr, "Info, generating DH parameters ... "); + fflush(stderr); + if(!(dh = DH_new()) || !DH_generate_parameters_ex(dh, 512, + DH_GENERATOR_5, NULL)) { + fprintf(stderr, "error!\n"); + if(dh) + DH_free(dh); + return 0; + } + fprintf(stderr, "complete\n"); + goto do_it; + } + /* So, we're loading dh_file */ + if((fp = fopen(dh_file, "r")) == NULL) { + fprintf(stderr, "Error, couldn't open '%s' for DH parameters\n", + dh_file); + return 0; + } + dh = PEM_read_DHparams(fp, NULL, NULL, NULL); + fclose(fp); + if(dh == NULL) { + fprintf(stderr, "Error, could not parse DH parameters from '%s'\n", + dh_file); + return 0; + } + fprintf(stderr, "Info, using DH parameters from file '%s'\n", dh_file); +do_it: + SSL_CTX_set_tmp_dh(ctx, dh); + DH_free(dh); + return 1; +} + +static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, + const char *CAfile, const char *cert, const char *key, + const char *dcert, const char *dkey, const char *cipher_list, + const char *dh_file, const char *dh_special, int tmp_rsa, + int ctx_options, int out_state, int out_verify, int verify_mode, + unsigned int verify_depth) +{ + SSL_CTX *ctx = NULL, *ret = NULL; + const SSL_METHOD *meth; + ENGINE *e = NULL; + + OpenSSL_add_ssl_algorithms(); + SSL_load_error_strings(); + + meth = (server_mode ? SSLv23_server_method() : SSLv23_client_method()); + if(meth == NULL) + goto err; + if(engine_id) { + ENGINE_load_builtin_engines(); + if((e = ENGINE_by_id(engine_id)) == NULL) { + fprintf(stderr, "Error obtaining '%s' engine, openssl " + "errors follow\n", engine_id); + goto err; + } + if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { + fprintf(stderr, "Error assigning '%s' engine, openssl " + "errors follow\n", engine_id); + goto err; + } + ENGINE_free(e); + } + if((ctx = SSL_CTX_new(meth)) == NULL) + goto err; + /* cacert */ + if(CAfile) { + if(!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx), + CAfile, NULL)) { + fprintf(stderr, "Error loading CA cert(s) in '%s'\n", + CAfile); + goto err; + } + fprintf(stderr, "Info, operating with CA cert(s) in '%s'\n", + CAfile); + } else + fprintf(stderr, "Info, operating without a CA cert(-list)\n"); + if(!SSL_CTX_set_default_verify_paths(ctx)) { + fprintf(stderr, "Error setting default verify paths\n"); + goto err; + } + + /* cert and key */ + if((cert || key) && !ctx_set_cert(ctx, cert, key)) + goto err; + /* dcert and dkey */ + if((dcert || dkey) && !ctx_set_cert(ctx, dcert, dkey)) + goto err; + /* temporary RSA key generation */ + if(tmp_rsa) + SSL_CTX_set_tmp_rsa_callback(ctx, cb_generate_tmp_rsa); + + /* cipher_list */ + if(cipher_list) { + if(!SSL_CTX_set_cipher_list(ctx, cipher_list)) { + fprintf(stderr, "Error setting cipher list '%s'\n", + cipher_list); + goto err; + } + fprintf(stderr, "Info, set cipher list '%s'\n", cipher_list); + } else + fprintf(stderr, "Info, operating with default cipher list\n"); + + /* dh_file & dh_special */ + if((dh_file || dh_special) && !ctx_set_dh(ctx, dh_file, dh_special)) + goto err; + + /* ctx_options */ + SSL_CTX_set_options(ctx, ctx_options); + + /* out_state (output of SSL handshake states to screen). */ + if(out_state) + cb_ssl_info_set_output(stderr); + + /* out_verify */ + if(out_verify > 0) { + cb_ssl_verify_set_output(stderr); + cb_ssl_verify_set_level(out_verify); + } + + /* verify_depth */ + cb_ssl_verify_set_depth(verify_depth); + + /* Success! (includes setting verify_mode) */ + SSL_CTX_set_info_callback(ctx, cb_ssl_info); + SSL_CTX_set_verify(ctx, verify_mode, cb_ssl_verify); + ret = ctx; +err: + if(!ret) { + ERR_print_errors_fp(stderr); + if(ctx) + SSL_CTX_free(ctx); + } + return ret; +} + +/*****************/ +/* Selector bits */ +/*****************/ + +static void selector_sets_init(select_sets_t *s) +{ + s->max = 0; + FD_ZERO(&s->reads); + FD_ZERO(&s->sends); + FD_ZERO(&s->excepts); +} +static void selector_init(tunala_selector_t *selector) +{ + selector_sets_init(&selector->last_selected); + selector_sets_init(&selector->next_select); +} + +#define SEL_EXCEPTS 0x00 +#define SEL_READS 0x01 +#define SEL_SENDS 0x02 +static void selector_add_raw_fd(tunala_selector_t *s, int fd, int flags) +{ + FD_SET(fd, &s->next_select.excepts); + if(flags & SEL_READS) + FD_SET(fd, &s->next_select.reads); + if(flags & SEL_SENDS) + FD_SET(fd, &s->next_select.sends); + /* Adjust "max" */ + if(s->next_select.max < (fd + 1)) + s->next_select.max = fd + 1; +} + +static void selector_add_listener(tunala_selector_t *selector, int fd) +{ + selector_add_raw_fd(selector, fd, SEL_READS); +} + +static void selector_add_tunala(tunala_selector_t *s, tunala_item_t *t) +{ + /* Set clean read if sm.clean_in is not full */ + if(t->clean_read != -1) { + selector_add_raw_fd(s, t->clean_read, + (buffer_full(state_machine_get_buffer(&t->sm, + SM_CLEAN_IN)) ? SEL_EXCEPTS : SEL_READS)); + } + /* Set clean send if sm.clean_out is not empty */ + if(t->clean_send != -1) { + selector_add_raw_fd(s, t->clean_send, + (buffer_empty(state_machine_get_buffer(&t->sm, + SM_CLEAN_OUT)) ? SEL_EXCEPTS : SEL_SENDS)); + } + /* Set dirty read if sm.dirty_in is not full */ + if(t->dirty_read != -1) { + selector_add_raw_fd(s, t->dirty_read, + (buffer_full(state_machine_get_buffer(&t->sm, + SM_DIRTY_IN)) ? SEL_EXCEPTS : SEL_READS)); + } + /* Set dirty send if sm.dirty_out is not empty */ + if(t->dirty_send != -1) { + selector_add_raw_fd(s, t->dirty_send, + (buffer_empty(state_machine_get_buffer(&t->sm, + SM_DIRTY_OUT)) ? SEL_EXCEPTS : SEL_SENDS)); + } +} + +static int selector_select(tunala_selector_t *selector) +{ + memcpy(&selector->last_selected, &selector->next_select, + sizeof(select_sets_t)); + selector_sets_init(&selector->next_select); + return select(selector->last_selected.max, + &selector->last_selected.reads, + &selector->last_selected.sends, + &selector->last_selected.excepts, NULL); +} + +/* This returns -1 for error, 0 for no new connections, or 1 for success, in + * which case *newfd is populated. */ +static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd) +{ + if(FD_ISSET(fd, &selector->last_selected.excepts)) + return -1; + if(!FD_ISSET(fd, &selector->last_selected.reads)) + return 0; + if((*newfd = ip_accept_connection(fd)) == -1) + return -1; + return 1; +} + +/************************/ +/* "Tunala" world stuff */ +/************************/ + +static int tunala_world_make_room(tunala_world_t *world) +{ + unsigned int newsize; + tunala_item_t *newarray; + + if(world->tunnels_used < world->tunnels_size) + return 1; + newsize = (world->tunnels_size == 0 ? 16 : + ((world->tunnels_size * 3) / 2)); + if((newarray = malloc(newsize * sizeof(tunala_item_t))) == NULL) + return 0; + memset(newarray, 0, newsize * sizeof(tunala_item_t)); + if(world->tunnels_used > 0) + memcpy(newarray, world->tunnels, + world->tunnels_used * sizeof(tunala_item_t)); + if(world->tunnels_size > 0) + free(world->tunnels); + /* migrate */ + world->tunnels = newarray; + world->tunnels_size = newsize; + return 1; +} + +static int tunala_world_new_item(tunala_world_t *world, int fd, + const char *ip, unsigned short port, int flipped) +{ + tunala_item_t *item; + int newfd; + SSL *new_ssl = NULL; + + if(!tunala_world_make_room(world)) + return 0; + if((new_ssl = SSL_new(world->ssl_ctx)) == NULL) { + fprintf(stderr, "Error creating new SSL\n"); + ERR_print_errors_fp(stderr); + return 0; + } + item = world->tunnels + (world->tunnels_used++); + state_machine_init(&item->sm); + item->clean_read = item->clean_send = + item->dirty_read = item->dirty_send = -1; + if((newfd = ip_create_connection_split(ip, port)) == -1) + goto err; + /* Which way round? If we're a server, "fd" is the dirty side and the + * connection we open is the clean one. For a client, it's the other way + * around. Unless, of course, we're "flipped" in which case everything + * gets reversed. :-) */ + if((world->server_mode && !flipped) || + (!world->server_mode && flipped)) { + item->dirty_read = item->dirty_send = fd; + item->clean_read = item->clean_send = newfd; + } else { + item->clean_read = item->clean_send = fd; + item->dirty_read = item->dirty_send = newfd; + } + /* We use the SSL's "app_data" to indicate a call-back induced "kill" */ + SSL_set_app_data(new_ssl, NULL); + if(!state_machine_set_SSL(&item->sm, new_ssl, world->server_mode)) + goto err; + return 1; +err: + tunala_world_del_item(world, world->tunnels_used - 1); + return 0; + +} + +static void tunala_world_del_item(tunala_world_t *world, unsigned int idx) +{ + tunala_item_t *item = world->tunnels + idx; + if(item->clean_read != -1) + close(item->clean_read); + if(item->clean_send != item->clean_read) + close(item->clean_send); + item->clean_read = item->clean_send = -1; + if(item->dirty_read != -1) + close(item->dirty_read); + if(item->dirty_send != item->dirty_read) + close(item->dirty_send); + item->dirty_read = item->dirty_send = -1; + state_machine_close(&item->sm); + /* OK, now we fix the item array */ + if(idx + 1 < world->tunnels_used) + /* We need to scroll entries to the left */ + memmove(world->tunnels + idx, + world->tunnels + (idx + 1), + (world->tunnels_used - (idx + 1)) * + sizeof(tunala_item_t)); + world->tunnels_used--; +} + +static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item) +{ + int c_r, c_s, d_r, d_s; /* Four boolean flags */ + + /* Take ourselves out of the gene-pool if there was an except */ + if((item->clean_read != -1) && FD_ISSET(item->clean_read, + &selector->last_selected.excepts)) + return 0; + if((item->clean_send != -1) && FD_ISSET(item->clean_send, + &selector->last_selected.excepts)) + return 0; + if((item->dirty_read != -1) && FD_ISSET(item->dirty_read, + &selector->last_selected.excepts)) + return 0; + if((item->dirty_send != -1) && FD_ISSET(item->dirty_send, + &selector->last_selected.excepts)) + return 0; + /* Grab our 4 IO flags */ + c_r = c_s = d_r = d_s = 0; + if(item->clean_read != -1) + c_r = FD_ISSET(item->clean_read, &selector->last_selected.reads); + if(item->clean_send != -1) + c_s = FD_ISSET(item->clean_send, &selector->last_selected.sends); + if(item->dirty_read != -1) + d_r = FD_ISSET(item->dirty_read, &selector->last_selected.reads); + if(item->dirty_send != -1) + d_s = FD_ISSET(item->dirty_send, &selector->last_selected.sends); + /* If no IO has happened for us, skip needless data looping */ + if(!c_r && !c_s && !d_r && !d_s) + return 1; + if(c_r) + c_r = (buffer_from_fd(state_machine_get_buffer(&item->sm, + SM_CLEAN_IN), item->clean_read) <= 0); + if(c_s) + c_s = (buffer_to_fd(state_machine_get_buffer(&item->sm, + SM_CLEAN_OUT), item->clean_send) <= 0); + if(d_r) + d_r = (buffer_from_fd(state_machine_get_buffer(&item->sm, + SM_DIRTY_IN), item->dirty_read) <= 0); + if(d_s) + d_s = (buffer_to_fd(state_machine_get_buffer(&item->sm, + SM_DIRTY_OUT), item->dirty_send) <= 0); + /* If any of the flags is non-zero, that means they need closing */ + if(c_r) { + close(item->clean_read); + if(item->clean_send == item->clean_read) + item->clean_send = -1; + item->clean_read = -1; + } + if(c_s && (item->clean_send != -1)) { + close(item->clean_send); + if(item->clean_send == item->clean_read) + item->clean_read = -1; + item->clean_send = -1; + } + if(d_r) { + close(item->dirty_read); + if(item->dirty_send == item->dirty_read) + item->dirty_send = -1; + item->dirty_read = -1; + } + if(d_s && (item->dirty_send != -1)) { + close(item->dirty_send); + if(item->dirty_send == item->dirty_read) + item->dirty_read = -1; + item->dirty_send = -1; + } + /* This function name is attributed to the term donated by David + * Schwartz on openssl-dev, message-ID: + * . :-) */ + if(!state_machine_churn(&item->sm)) + /* If the SSL closes, it will also zero-out the _in buffers + * and will in future process just outgoing data. As and + * when the outgoing data has gone, it will return zero + * here to tell us to bail out. */ + return 0; + /* Otherwise, we return zero if both sides are dead. */ + if(((item->clean_read == -1) || (item->clean_send == -1)) && + ((item->dirty_read == -1) || (item->dirty_send == -1))) + return 0; + /* If only one side closed, notify the SSL of this so it can take + * appropriate action. */ + if((item->clean_read == -1) || (item->clean_send == -1)) { + if(!state_machine_close_clean(&item->sm)) + return 0; + } + if((item->dirty_read == -1) || (item->dirty_send == -1)) { + if(!state_machine_close_dirty(&item->sm)) + return 0; + } + return 1; +} + diff --git a/demos/tunala/tunala.h b/demos/tunala/tunala.h new file mode 100644 index 0000000..3a752f2 --- /dev/null +++ b/demos/tunala/tunala.h @@ -0,0 +1,215 @@ +/* Tunala ("Tunneler with a New Zealand accent") + * + * Written by Geoff Thorpe, but endorsed/supported by noone. Please use this is + * if it's useful or informative to you, but it's only here as a scratchpad for + * ideas about how you might (or might not) program with OpenSSL. If you deploy + * this is in a mission-critical environment, and have not read, understood, + * audited, and modified this code to your satisfaction, and the result is that + * all hell breaks loose and you are looking for a new employer, then it proves + * nothing except perhaps that Darwinism is alive and well. Let's just say, *I* + * don't use this in a mission-critical environment, so it would be stupid for + * anyone to assume that it is solid and/or tested enough when even its author + * doesn't place that much trust in it. You have been warned. + * + * With thanks to Cryptographic Appliances, Inc. + */ + +#ifndef _TUNALA_H +#define _TUNALA_H + +/* pull in autoconf fluff */ +#ifndef NO_CONFIG_H +#include "config.h" +#else +/* We don't have autoconf, we have to set all of these unless a tweaked Makefile + * tells us not to ... */ +/* headers */ +#ifndef NO_HAVE_SELECT +#define HAVE_SELECT +#endif +#ifndef NO_HAVE_SOCKET +#define HAVE_SOCKET +#endif +#ifndef NO_HAVE_UNISTD_H +#define HAVE_UNISTD_H +#endif +#ifndef NO_HAVE_FCNTL_H +#define HAVE_FCNTL_H +#endif +#ifndef NO_HAVE_LIMITS_H +#define HAVE_LIMITS_H +#endif +/* features */ +#ifndef NO_HAVE_STRSTR +#define HAVE_STRSTR +#endif +#ifndef NO_HAVE_STRTOUL +#define HAVE_STRTOUL +#endif +#endif + +#if !defined(HAVE_SELECT) || !defined(HAVE_SOCKET) +#error "can't build without some network basics like select() and socket()" +#endif + +#include +#ifndef NO_SYSTEM_H +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#include +#include +#include +#include +#include +#endif /* !defined(NO_SYSTEM_H) */ + +#ifndef NO_OPENSSL +#include +#include +#include +#endif /* !defined(NO_OPENSSL) */ + +#ifndef OPENSSL_NO_BUFFER +/* This is the generic "buffer" type that is used when feeding the + * state-machine. It's basically a FIFO with respect to the "adddata" & + * "takedata" type functions that operate on it. */ +#define MAX_DATA_SIZE 16384 +typedef struct _buffer_t { + unsigned char data[MAX_DATA_SIZE]; + unsigned int used; + /* Statistical values - counts the total number of bytes read in and + * read out (respectively) since "buffer_init()" */ + unsigned long total_in, total_out; +} buffer_t; + +/* Initialise a buffer structure before use */ +void buffer_init(buffer_t *buf); +/* Cleanup a buffer structure - presently not needed, but if buffer_t is + * converted to using dynamic allocation, this would be required - so should be + * called to protect against an explosion of memory leaks later if the change is + * made. */ +void buffer_close(buffer_t *buf); + +/* Basic functions to manipulate buffers */ + +unsigned int buffer_used(buffer_t *buf); /* How much data in the buffer */ +unsigned int buffer_unused(buffer_t *buf); /* How much space in the buffer */ +int buffer_full(buffer_t *buf); /* Boolean, is it full? */ +int buffer_notfull(buffer_t *buf); /* Boolean, is it not full? */ +int buffer_empty(buffer_t *buf); /* Boolean, is it empty? */ +int buffer_notempty(buffer_t *buf); /* Boolean, is it not empty? */ +unsigned long buffer_total_in(buffer_t *buf); /* Total bytes written to buffer */ +unsigned long buffer_total_out(buffer_t *buf); /* Total bytes read from buffer */ + +#if 0 /* Currently used only within buffer.c - better to expose only + * higher-level functions anyway */ +/* Add data to the tail of the buffer, returns the amount that was actually + * added (so, you need to check if return value is less than size) */ +unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr, + unsigned int size); + +/* Take data from the front of the buffer (and scroll the rest forward). If + * "ptr" is NULL, this just removes data off the front of the buffer. Return + * value is the amount actually removed (can be less than size if the buffer has + * too little data). */ +unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr, + unsigned int size); + +/* Flushes as much data as possible out of the "from" buffer into the "to" + * buffer. Return value is the amount moved. The amount moved can be restricted + * to a maximum by specifying "cap" - setting it to -1 means no limit. */ +unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap); +#endif + +#ifndef NO_IP +/* Read or write between a file-descriptor and a buffer */ +int buffer_from_fd(buffer_t *buf, int fd); +int buffer_to_fd(buffer_t *buf, int fd); +#endif /* !defined(NO_IP) */ + +#ifndef NO_OPENSSL +/* Read or write between an SSL or BIO and a buffer */ +void buffer_from_SSL(buffer_t *buf, SSL *ssl); +void buffer_to_SSL(buffer_t *buf, SSL *ssl); +void buffer_from_BIO(buffer_t *buf, BIO *bio); +void buffer_to_BIO(buffer_t *buf, BIO *bio); + +/* Callbacks */ +void cb_ssl_info(const SSL *s, int where, int ret); +void cb_ssl_info_set_output(FILE *fp); /* Called if output should be sent too */ +int cb_ssl_verify(int ok, X509_STORE_CTX *ctx); +void cb_ssl_verify_set_output(FILE *fp); +void cb_ssl_verify_set_depth(unsigned int verify_depth); +void cb_ssl_verify_set_level(unsigned int level); +RSA *cb_generate_tmp_rsa(SSL *s, int is_export, int keylength); +#endif /* !defined(NO_OPENSSL) */ +#endif /* !defined(OPENSSL_NO_BUFFER) */ + +#ifndef NO_TUNALA +#ifdef OPENSSL_NO_BUFFER +#error "TUNALA section of tunala.h requires BUFFER support" +#endif +typedef struct _state_machine_t { + SSL *ssl; + BIO *bio_intossl; + BIO *bio_fromssl; + buffer_t clean_in, clean_out; + buffer_t dirty_in, dirty_out; +} state_machine_t; +typedef enum { + SM_CLEAN_IN, SM_CLEAN_OUT, + SM_DIRTY_IN, SM_DIRTY_OUT +} sm_buffer_t; +void state_machine_init(state_machine_t *machine); +void state_machine_close(state_machine_t *machine); +buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type); +SSL *state_machine_get_SSL(state_machine_t *machine); +int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server); +/* Performs the data-IO loop and returns zero if the machine should close */ +int state_machine_churn(state_machine_t *machine); +/* Is used to handle closing conditions - namely when one side of the tunnel has + * closed but the other should finish flushing. */ +int state_machine_close_clean(state_machine_t *machine); +int state_machine_close_dirty(state_machine_t *machine); +#endif /* !defined(NO_TUNALA) */ + +#ifndef NO_IP +/* Initialise anything related to the networking. This includes blocking pesky + * SIGPIPE signals. */ +int ip_initialise(void); +/* ip is the 4-byte ip address (eg. 127.0.0.1 is {0x7F,0x00,0x00,0x01}), port is + * the port to listen on (host byte order), and the return value is the + * file-descriptor or -1 on error. */ +int ip_create_listener_split(const char *ip, unsigned short port); +/* Same semantics as above. */ +int ip_create_connection_split(const char *ip, unsigned short port); +/* Converts a string into the ip/port before calling the above */ +int ip_create_listener(const char *address); +int ip_create_connection(const char *address); +/* Just does a string conversion on its own. NB: If accept_all_ip is non-zero, + * then the address string could be just a port. Ie. it's suitable for a + * listening address but not a connecting address. */ +int ip_parse_address(const char *address, const char **parsed_ip, + unsigned short *port, int accept_all_ip); +/* Accepts an incoming connection through the listener. Assumes selects and + * what-not have deemed it an appropriate thing to do. */ +int ip_accept_connection(int listen_fd); +#endif /* !defined(NO_IP) */ + +/* These functions wrap up things that can be portability hassles. */ +int int_strtoul(const char *str, unsigned long *val); +#ifdef HAVE_STRSTR +#define int_strstr strstr +#else +char *int_strstr(const char *haystack, const char *needle); +#endif + +#endif /* !defined(_TUNALA_H) */ diff --git a/demos/x509/README b/demos/x509/README new file mode 100644 index 0000000..88f9d6c --- /dev/null +++ b/demos/x509/README @@ -0,0 +1,3 @@ +This directory contains examples of how to contruct +various X509 structures. Certificates, certificate requests +and CRLs. diff --git a/demos/x509/mkcert.c b/demos/x509/mkcert.c new file mode 100644 index 0000000..6a52e5d --- /dev/null +++ b/demos/x509/mkcert.c @@ -0,0 +1,172 @@ +/* Certificate creation. Demonstrates some certificate related + * operations. + */ + + +#include +#include + +#include +#include +#include +#ifndef OPENSSL_NO_ENGINE +#include +#endif + +int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days); +int add_ext(X509 *cert, int nid, char *value); + +int main(int argc, char **argv) + { + BIO *bio_err; + X509 *x509=NULL; + EVP_PKEY *pkey=NULL; + + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + + bio_err=BIO_new_fp(stderr, BIO_NOCLOSE); + + mkcert(&x509,&pkey,512,0,365); + + RSA_print_fp(stdout,pkey->pkey.rsa,0); + X509_print_fp(stdout,x509); + + PEM_write_PrivateKey(stdout,pkey,NULL,NULL,0,NULL, NULL); + PEM_write_X509(stdout,x509); + + X509_free(x509); + EVP_PKEY_free(pkey); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_cleanup(); +#endif + CRYPTO_cleanup_all_ex_data(); + + CRYPTO_mem_leaks(bio_err); + BIO_free(bio_err); + return(0); + } + +static void callback(int p, int n, void *arg) + { + char c='B'; + + if (p == 0) c='.'; + if (p == 1) c='+'; + if (p == 2) c='*'; + if (p == 3) c='\n'; + fputc(c,stderr); + } + +int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days) + { + X509 *x; + EVP_PKEY *pk; + RSA *rsa; + X509_NAME *name=NULL; + + if ((pkeyp == NULL) || (*pkeyp == NULL)) + { + if ((pk=EVP_PKEY_new()) == NULL) + { + abort(); + return(0); + } + } + else + pk= *pkeyp; + + if ((x509p == NULL) || (*x509p == NULL)) + { + if ((x=X509_new()) == NULL) + goto err; + } + else + x= *x509p; + + rsa=RSA_generate_key(bits,RSA_F4,callback,NULL); + if (!EVP_PKEY_assign_RSA(pk,rsa)) + { + abort(); + goto err; + } + rsa=NULL; + + X509_set_version(x,2); + ASN1_INTEGER_set(X509_get_serialNumber(x),serial); + X509_gmtime_adj(X509_get_notBefore(x),0); + X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days); + X509_set_pubkey(x,pk); + + name=X509_get_subject_name(x); + + /* This function creates and adds the entry, working out the + * correct string type and performing checks on its length. + * Normally we'd check the return value for errors... + */ + X509_NAME_add_entry_by_txt(name,"C", + MBSTRING_ASC, "UK", -1, -1, 0); + X509_NAME_add_entry_by_txt(name,"CN", + MBSTRING_ASC, "OpenSSL Group", -1, -1, 0); + + /* Its self signed so set the issuer name to be the same as the + * subject. + */ + X509_set_issuer_name(x,name); + + /* Add various extensions: standard extensions */ + add_ext(x, NID_basic_constraints, "critical,CA:TRUE"); + add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign"); + + add_ext(x, NID_subject_key_identifier, "hash"); + + /* Some Netscape specific extensions */ + add_ext(x, NID_netscape_cert_type, "sslCA"); + + add_ext(x, NID_netscape_comment, "example comment extension"); + + +#ifdef CUSTOM_EXT + /* Maybe even add our own extension based on existing */ + { + int nid; + nid = OBJ_create("1.2.3.4", "MyAlias", "My Test Alias Extension"); + X509V3_EXT_add_alias(nid, NID_netscape_comment); + add_ext(x, nid, "example comment alias"); + } +#endif + + if (!X509_sign(x,pk,EVP_sha1())) + goto err; + + *x509p=x; + *pkeyp=pk; + return(1); +err: + return(0); + } + +/* Add extension using V3 code: we can set the config file as NULL + * because we wont reference any other sections. + */ + +int add_ext(X509 *cert, int nid, char *value) + { + X509_EXTENSION *ex; + X509V3_CTX ctx; + /* This sets the 'context' of the extensions. */ + /* No configuration database */ + X509V3_set_ctx_nodb(&ctx); + /* Issuer and subject certs: both the target since it is self signed, + * no request and no CRL + */ + X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0); + ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value); + if (!ex) + return 0; + + X509_add_ext(cert,ex,-1); + X509_EXTENSION_free(ex); + return 1; + } + diff --git a/demos/x509/mkreq.c b/demos/x509/mkreq.c new file mode 100644 index 0000000..d17e4ad --- /dev/null +++ b/demos/x509/mkreq.c @@ -0,0 +1,161 @@ +/* Certificate request creation. Demonstrates some request related + * operations. + */ + +#include +#include + +#include +#include +#include +#ifndef OPENSSL_NO_ENGINE +#include +#endif + +int mkreq(X509_REQ **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days); +int add_ext(STACK_OF(X509_REQUEST) *sk, int nid, char *value); + +int main(int argc, char **argv) + { + BIO *bio_err; + X509_REQ *req=NULL; + EVP_PKEY *pkey=NULL; + + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + + bio_err=BIO_new_fp(stderr, BIO_NOCLOSE); + + mkreq(&req,&pkey,512,0,365); + + RSA_print_fp(stdout,pkey->pkey.rsa,0); + X509_REQ_print_fp(stdout,req); + + PEM_write_X509_REQ(stdout,req); + + X509_REQ_free(req); + EVP_PKEY_free(pkey); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_cleanup(); +#endif + CRYPTO_cleanup_all_ex_data(); + + CRYPTO_mem_leaks(bio_err); + BIO_free(bio_err); + return(0); + } + +static void callback(int p, int n, void *arg) + { + char c='B'; + + if (p == 0) c='.'; + if (p == 1) c='+'; + if (p == 2) c='*'; + if (p == 3) c='\n'; + fputc(c,stderr); + } + +int mkreq(X509_REQ **req, EVP_PKEY **pkeyp, int bits, int serial, int days) + { + X509_REQ *x; + EVP_PKEY *pk; + RSA *rsa; + X509_NAME *name=NULL; + STACK_OF(X509_EXTENSION) *exts = NULL; + + if ((pk=EVP_PKEY_new()) == NULL) + goto err; + + if ((x=X509_REQ_new()) == NULL) + goto err; + + rsa=RSA_generate_key(bits,RSA_F4,callback,NULL); + if (!EVP_PKEY_assign_RSA(pk,rsa)) + goto err; + + rsa=NULL; + + X509_REQ_set_pubkey(x,pk); + + name=X509_REQ_get_subject_name(x); + + /* This function creates and adds the entry, working out the + * correct string type and performing checks on its length. + * Normally we'd check the return value for errors... + */ + X509_NAME_add_entry_by_txt(name,"C", + MBSTRING_ASC, "UK", -1, -1, 0); + X509_NAME_add_entry_by_txt(name,"CN", + MBSTRING_ASC, "OpenSSL Group", -1, -1, 0); + +#ifdef REQUEST_EXTENSIONS + /* Certificate requests can contain extensions, which can be used + * to indicate the extensions the requestor would like added to + * their certificate. CAs might ignore them however or even choke + * if they are present. + */ + + /* For request extensions they are all packed in a single attribute. + * We save them in a STACK and add them all at once later... + */ + + exts = sk_X509_EXTENSION_new_null(); + /* Standard extenions */ + + add_ext(exts, NID_key_usage, "critical,digitalSignature,keyEncipherment"); + + /* This is a typical use for request extensions: requesting a value for + * subject alternative name. + */ + + add_ext(exts, NID_subject_alt_name, "email:steve@openssl.org"); + + /* Some Netscape specific extensions */ + add_ext(exts, NID_netscape_cert_type, "client,email"); + + + +#ifdef CUSTOM_EXT + /* Maybe even add our own extension based on existing */ + { + int nid; + nid = OBJ_create("1.2.3.4", "MyAlias", "My Test Alias Extension"); + X509V3_EXT_add_alias(nid, NID_netscape_comment); + add_ext(x, nid, "example comment alias"); + } +#endif + + /* Now we've created the extensions we add them to the request */ + + X509_REQ_add_extensions(x, exts); + + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + +#endif + + if (!X509_REQ_sign(x,pk,EVP_sha1())) + goto err; + + *req=x; + *pkeyp=pk; + return(1); +err: + return(0); + } + +/* Add extension using V3 code: we can set the config file as NULL + * because we wont reference any other sections. + */ + +int add_ext(STACK_OF(X509_REQUEST) *sk, int nid, char *value) + { + X509_EXTENSION *ex; + ex = X509V3_EXT_conf_nid(NULL, NULL, nid, value); + if (!ex) + return 0; + sk_X509_EXTENSION_push(sk, ex); + + return 1; + } + -- cgit v1.2.3