How to use X509_verify() - c++

How can we use X509_verify(). I have two certificates. The first certificate is the Root Certificate which signed the next certificate (which is my Certificate). So I want to check if my certificate is signed by the root certificate using x509_verify() in C++. My goal is to keep the code simple and Understandable so I can also put it online.

Signature of X509_verify is
int X509_verify(X509 * x509, EVP_PKEY * pkey);
Suppose of you have root certificate in root and your certificate in mycert;
X509 * root;
X509 * mycert;
//Get root certificate into root
//Get mycert into mycert.
//Get the public key.
EVP_PKEY * pubkey = X509_get_pubkey(root);
//verify. result less than or 0 means not verified or some error.
int result = X509_verify(mycert, pubkey);
//free the public key.
EVP_PKEY_free(pubkey);
I think this would help you.

I think dbasic and Balamurugan answered how to use it. Here's how to interpret the errors you get from it. I find error handling is much more important than business logic because nearly anyone can copy/paste code that works in a benign environment. How you respond to failures, broken/bad inputs and a hostile environments matter more.
The source code for the function is in <openssl dir>/crypto/x509/x_all.c:
int X509_verify(X509 *a, EVP_PKEY *r)
{
return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF),a->sig_alg,
a->signature,a->cert_info,r));
}
ASN1_item_verify id defined in <openssl dir>/crypto/asn1/a_verify.c:
int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *alg,
ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey)
{
...
}
The function returns -1 on failure with one of the following error codes:
ERR_R_PASSED_NULL_PARAMETER if pkey is NULL
ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM if alg is unknown using an OID lookup
ASN1_R_WRONG_PUBLIC_KEY_TYPE if the pkey type does not match the pkey->method
ERR_R_MALLOC_FAILURE if a buffer allocation fails
The function returns 0 on failure with one of the following error codes:
ERR_R_EVP_LIB if EVP_DigestVerifyInit fails
ERR_R_EVP_LIB if EVP_DigestVerifyUpdate fails
ERR_R_EVP_LIB if EVP_DigestVerifyFinal fails
On success, the function returns 1 (from around line 220):
...
if (EVP_DigestVerifyFinal(&ctx,signature->data,
(size_t)signature->length) <= 0)
{
ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
ret=0;
goto err;
}
ret=1;
err:
EVP_MD_CTX_cleanup(&ctx);
return(ret);
} /* End of function */
From <openssl dir>/crypto/err/err.h, you use ERR_get_error() to retrieve the error code:
err.h:#define ASN1err(f,r) ERR_PUT_error(ERR_LIB_ASN1,(f),(r),__FILE__,__LINE__)

Step1 : Read the certificate and convert the Certificate into X509 structure
// the below will show how to read the certificate from the file (DER or PEM Encoded)
X509* oCertificate=NULL;
FILE *lFp=NULL;
lFp=fopen(iFilePath.c_str(),"rb"); // iFilepath is the string
if(lFp==NULL)
{
oCertificate=NULL;
}
else
{
oCertificate = PEM_read_X509(lFp, NULL, NULL, NULL);
if (oCertificate == NULL )
{
//Certificate may be DER encode
oCertificate = d2i_X509_fp(lFp, NULL);
}
fclose(lFp);
}
// OCertificate contains
Step 2: now read the Root certificate key
(Note check the X509 is NULL or not before use)
Step 3 : use the X509_verify() function.

Related

C++ OpenSSL: libssl fails to verify certificates on Windows

I've done a lot of looking around but I can't seem to find a decent solution to this problem. Many of the StackOverflow posts are regarding Ruby, but I'm using OpenSSL more or less directly (via the https://gitlab.com/eidheim/Simple-Web-Server library) for a C++ application/set of libraries, and need to work out how to fix this completely transparently for users (they should not need to hook up any custom certificate verification file in order to use the application).
On Windows, when I attempt to use the SimpleWeb HTTPS client, connections fail if I have certificate verification switched on, because the certificate for the connection fails to validate. This is not the case on Linux, where verification works fine.
I was advised to follow this solution to import the Windows root certificates into OpenSSL so that they could be used by the verification routines. However, this doesn't seem to make any difference as far as I can see. I have dug into the guts of the libssl verification functions to try and understand exactly what's going on, and although the above answer recommends adding the Windows root certificates to a new X509_STORE, it appears that the SSL connection context has its own store which is set up when the connection is initialised. This makes me think that simply creating a new X509_STORE and adding certificates there is not helping because the connection doesn't actually use that store.
It may well be that I've spent so much time debugging the minutiae of libssl that I'm missing what the actual approach to solving this problem should be. Does OpenSSL provide a canonical way of looking up system certificates that I'm not setting? Alternatively, could the issue be the way that the SimpleWeb library/ASIO is initialising OpenSSL? I know that the library allows you to provide a path for a "verify file" for certificates, but I feel like this wouldn't be an appropriate solution since I as a developer should be using the certificates found on the end user's system, rather than hard-coding my own.
EDIT: For context, this is the code I'm using in a tiny example application:
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
static void LoadSystemCertificates()
{
HCERTSTORE hStore;
PCCERT_CONTEXT pContext = nullptr;
X509 *x509 = nullptr;
X509_STORE *store = X509_STORE_new();
hStore = CertOpenSystemStore(NULL, "ROOT");
if (!hStore)
{
return;
}
while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) != nullptr)
{
const unsigned char* encodedCert = reinterpret_cast<const unsigned char*>(pContext->pbCertEncoded);
x509 = d2i_X509(nullptr, &encodedCert, pContext->cbCertEncoded);
if (x509)
{
X509_STORE_add_cert(store, x509);
X509_free(x509);
}
}
CertCloseStore(hStore, 0);
}
static void MakeRequest(const std::string& address)
{
using Client = SimpleWeb::Client<SimpleWeb::HTTPS>;
Client httpsClient(address);
httpsClient.io_service = std::make_shared<asio::io_service>();
std::cout << "Making request to: " << address << std::endl;
bool hasResponse = false;
httpsClient.request("GET", [address, &hasResponse](std::shared_ptr<Client::Response> response, const SimpleWeb::error_code& error)
{
hasResponse = true;
if ( error )
{
std::cerr << "Got error from " << address << ": " << error.message() << std::endl;
}
else
{
std::cout << "Got response from " << address << ":\n" << response->content.string() << std::endl;
}
});
while ( !hasResponse )
{
httpsClient.io_service->poll();
httpsClient.io_service->reset();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
int main(int, char**)
{
LoadSystemCertificates();
MakeRequest("google.co.uk");
return 0;
}
The call returns me: Got error from google.co.uk: certificate verify failed
OK, to anyone who this might help in future, this is how I solved this issue. This answer to a related question helped.
It turns out that the issue was indeed that the SSL context was not making use of the certificate store that I'd set up. Everything else was OK, bu the missing piece of the puzzle was a call to SSL_CTX_set_cert_store(), which takes the certificate store and provides it to the SSL context.
In the context of the SimpleWeb library, the easiest way to do this appeared to be to subclass the SimpleWeb::Client<SimpleWeb::HTTPS> class and add the following to the constructor:
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <wincrypt.h>
class MyClient : public SimpleWeb::Client<SimpleWeb::HTTPS>
{
public:
MyClient( /* ... */ ) :
SimpleWeb::Client<SimpleWeb::HTTPS>( /* ... */ )
{
AddWindowsRootCertificates();
}
private:
using OpenSSLContext = asio::ssl::context::native_handle_type;
void AddWindowsRootCertificates()
{
// Get the SSL context from the SimpleWeb class.
OpenSSLContext sslContext = context.native_handle();
// Get a certificate store populated with the Windows root certificates.
// If this fails for some reason, the function returns null.
X509_STORE* certStore = GetWindowsCertificateStore();
if ( sslContext && certStore )
{
// Set this store to be used for the SSL context.
SSL_CTX_set_cert_store(sslContext, certStore);
}
}
static X509_STORE* GetWindowsCertificateStore()
{
// To avoid populating the store every time, we keep a static
// pointer to the store and just initialise it the first time
// this function is called.
static X509_STORE* certificateStore = nullptr;
if ( !certificateStore )
{
// Not initialised yet, so do so now.
// Try to open the root certificate store.
HCERTSTORE rootStore = CertOpenSystemStore(0, "ROOT");
if ( rootStore )
{
// The new store is reference counted, so we can create it
// and keep the pointer around for later use.
certificateStore = X509_STORE_new();
PCCERT_CONTEXT pContext = nullptr;
while ( (pContext = CertEnumCertificatesInStore(rootStore, pContext)) != nullptr )
{
// d2i_X509() may modify the pointer, so make a local copy.
const unsigned char* content = pContext->pbCertEncoded;
// Convert the certificate to X509 format.
X509 *x509 = d2i_X509(NULL, &content, pContext->cbCertEncoded);
if ( x509 )
{
// Successful conversion, so add to the store.
X509_STORE_add_cert(certificateStore, x509);
// Release our reference.
X509_free(x509);
}
}
// Make sure to close the store.
CertCloseStore(rootStore, 0);
}
}
return certificateStore;
}
};
Obviously GetWindowsCertificateStore() would need to be abstracted out to somewhere platform-specific if your class needs to compile on multiple platforms.

Add CRL number extension to CRL using OpenSSL

For some client testing I need to generate certificates and revocation lists "on the fly". I am able to setup a revocation list with the CRL number extension using OpenSSL console commands and configuration files. However I can't make this work in code.
Here are my relevant functions:
X509* g_certificate[MAX_CERTIFICATE_COUNT];
EVP_PKEY* g_certificateKeyPair[MAX_CERTIFICATE_COUNT];
X509_CRL* g_crl;
UINT16 GenerateCrl(UINT16 issuerCertificateIndex, UINT16 crlNumber, INT32 lastUpdate, INT32 nextUpdate)
{
ASN1_TIME* lastUpdateTime = ASN1_TIME_new();
ASN1_TIME* nextUpdateTime = ASN1_TIME_new();
char crlNumberString[32];
int result = 1;
if (g_crl != NULL) X509_CRL_free(g_crl);
g_crl = X509_CRL_new();
result &= X509_CRL_set_version(g_crl, 1);
result &= X509_CRL_set_issuer_name(g_crl, X509_get_subject_name(g_certificate[issuerCertificateIndex]));
// there are multiple X509 certificate objects stored in memory, which I use to setup certificate chains
ASN1_TIME_set(lastUpdateTime, time(NULL) + lastUpdate);
ASN1_TIME_set(nextUpdateTime, time(NULL) + nextUpdate);
result &= X509_CRL_set1_lastUpdate(g_crl, lastUpdateTime);
result &= X509_CRL_set1_nextUpdate(g_crl, nextUpdateTime);
ASN1_TIME_free(lastUpdateTime);
ASN1_TIME_free(nextUpdateTime);
_itoa_s((int)crlNumber, crlNumberString, 10);
// my CRLs need to have the authority key identifier and CRL number extensions
result &= SetCrlExtension(issuerCertificateIndex, NID_authority_key_identifier, "keyid:always"); // this does add the auth key id extension
result &= SetCrlExtension(issuerCertificateIndex, NID_crl_number, crlNumberString); // this does not add CRL number the extension
result &= X509_CRL_sign(g_crl, g_certificateKeyPair[issuerCertificateIndex], EVP_sha256());
return result;
}
INT16 SetCrlExtension(UINT16 issuerCertificateIndex, INT16 extensionNid, const char* extensionData)
{
X509V3_CTX ctx;
X509_EXTENSION* extension;
lhash_st_CONF_VALUE conf; // actually I have no idea what this is for, probably it is not required here
int result = 1;
X509V3_set_ctx(&ctx, g_certificate[issuerCertificateIndex], NULL, NULL, g_crl, 0);
extension = X509V3_EXT_conf_nid(&conf, &ctx, extensionNid, (char*)extensionData);
result &= X509_CRL_add_ext(g_crl, extension, -1);
return result;
}
void SaveCrlAsPem(const char* fileName)
{
FILE* f;
fopen_s(&f, fileName, "wb");
PEM_write_X509_CRL(f, g_crl);
if (f != NULL) fclose(f);
}
So e.g.
GenerateCrl(1, 1234, -3600, 36000);
SaveCrlAsPem("crl.pem");
should result in a CRL having said extension. But it does only contain the authority key identifier extension. Everything else is fine. Im also adding the certificate extensions in basically the same way and dont't have any issues there.
So how can I get the CRL number attached to my CRL?
You mention that you are able to setup the CRL number extension from OpenSSL command line. You should probably take a look at the source code of the particular command then.
I haven't used CRLs, but I believe you are using the ca command. Looking for NID_crl_number in its source at apps/ca.c (from OpenSSL 1.1.1g) shows the following code:
/* Add any extensions asked for */
if (crl_ext != NULL || crlnumberfile != NULL) {
X509V3_CTX crlctx;
X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0);
X509V3_set_nconf(&crlctx, conf);
if (crl_ext != NULL)
if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx, crl_ext, crl))
goto end;
if (crlnumberfile != NULL) {
tmpser = BN_to_ASN1_INTEGER(crlnumber, NULL);
if (!tmpser)
goto end;
X509_CRL_add1_ext_i2d(crl, NID_crl_number, tmpser, 0, 0);
ASN1_INTEGER_free(tmpser);
crl_v2 = 1;
if (!BN_add_word(crlnumber, 1))
goto end;
}
}
So, it seems you can use X509V3_EXT_CRL_add_nconf or X509_CRL_add1_ext_i2d for the purpose. Please refer the apps/ca.c of the OpenSSL version that you are using.
Another solution:
Maybe not the best approach, but you can probably launch the same OpenSSL commands as processes from code and process their output if it's acceptable.

How do I generate a DER encoded public key with OpenSSL in C/C++?

I have been developing a Minecraft server software and having some trouble generating a DER encoded public key with OpenSSL in C/C++.
https://wiki.vg/Protocol_Encryption (The documentation of making a server software) says this:
The server generates a 1024-bit RSA keypair on startup.
The public key is sent in the Encryption Request packet in DER encoding format.
More technically, it is in ASN.1 format as defined by x.509 with the structure looking as follows.
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm SEQUENCE {
algorithm OBJECT IDENTIFIER
parameters ANY OPTIONAL
}
subjectPublicKey BITSTRING
}
SubjectPublicKey ::= SEQUENCE {
modulus INTEGER
publicExponent INTEGER
}
Here is my current code:
RSA* rsa = RSA_new();
if (!rsa)
return false;
BIGNUM* exponent = BN_new();
if (!exponent)
{
RSA_free(rsa);
return false;
}
EVP_PKEY* pkey = EVP_PKEY_new();
if (!pkey)
{
RSA_free(rsa);
BN_free(exponent);
return false;
}
BN_set_word(exponent, 65537);
RSA_generate_key_ex(rsa, 1024, exponent, NULL);
EVP_PKEY_set1_RSA(pkey, rsa);
// Write the DER encoded public key
std::vector<uint8_t> derPublicKey;
{
derPublicKey.resize(1024);
X509* x509 = X509_new();
X509_set_pubkey(x509, pkey);
uint8_t* keyPtr = derPublicKey.data();
int keyLength;
if (!(keyLength = i2d_X509(x509, &keyPtr)))
{
RSA_free(rsa);
BN_free(exponent);
return false;
} derPublicKey.resize(keyLength);
X509_free(x509);
}
// Free everything
RSA_free(rsa);
BN_free(exponent);
EVP_PKEY_free(pkey);
This code compiles, but the client connecting still says in the log "Public key reconstitute failed" with no further information. Can someone explain how this can be done? Thanks.
PS: I have very little knowledge about cryptography. I am only doing this project for fun.

PEM_read_X509() exits with code 0

I am trying to use OpenSSL in Visual Studio 2010 to read a .pem file and parse an x509 certificate. I got my code example form This tutorial the certificate is formatted in base 64, is named 'secondtry.pem' and looks like this:
-----BEGIN CERTIFICATE-----
MIIDHjCCAtygAwIBAgIEIDJHfjALBgcqhkjOOAQDBQAwYTELMAkGA1UEBhMCVVMxCzAJBgNVBAgT
AkZMMRIwEAYDVQQHEwlNZWxib3VybmUxDjAMBgNVBAoTBU1vbnRoMQwwCgYDVQQLEwNEYXkxEzAR
BgNVBAMTCkp1bHkgRWlnaHQwHhcNMTUwNzA4MTMwNDA2WhcNMTUxMDA2MTMwNDA2WjBhMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCRkwxEjAQBgNVBAcTCU1lbGJvdXJuZTEOMAwGA1UEChMFTW9udGgx
DDAKBgNVBAsTA0RheTETMBEGA1UEAxMKSnVseSBFaWdodDCCAbcwggEsBgcqhkjOOAQBMIIBHwKB
gQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeB
O4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1
864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4
V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyN
KOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kq
A4GEAAKBgDH20wAdrFDjcp2hJm2M9y/tm+VCnQP5sL8knITNrDoJXrj6NEkDNkjIlJrXbrPpWuM+
uNbmFOZQAusHNX4gyRfoJCWRAIyOAQ5RsUOEb7isdjnxplbRipFF81NQXJ4XVsZ8wzTZ5quUFhq8
TWOb7Nw6GuaM9BA5tcQZgPMNrZo9oyEwHzAdBgNVHQ4EFgQUtPDQywlbEA/oCiMwN7OXBaxYqoow
CwYHKoZIzjgEAwUAAy8AMCwCFE8buS4tUi3zdlKJzZrnjmFVp8jrAhRnGgZ5/sxU9cTg+1IWZPHx
kBMc7A==
-----END CERTIFICATE-----
I have a function to open the .pem file and assign it to an X509 object for later parsing. Here is the function:
X509* openPemFile(char* filename)
{
X509* cert;
FILE* certfile = fopen(filename, "rb");
if(!certfile)
{
fprintf( stdout, "Unable to open file %s\n", filename);
return NULL;
}
PEM_read_X509(certfile, &cert, 0, NULL);
if(!cert)
{
fprintf(stdout, "Unable to parse certificate in: %s\n", filename);
fclose(certfile);
return NULL;
}
return cert;
}
I am calling the function like so:
X509* cert = openPemFile("secondtry.pem");
the file opens without error, but when my code gets to the line:
PEM_read_X509(certfile, &cert, 0, NULL);
it exits with "Native' has exited with code 0 (0x0)."
I have tried calling the PEM_read_x509 function several different ways:
X509* cert = PEM_read_X509(certfile, NULL, NULL, NULL);
PEM_read_X509(certfile, &cert, NULL, NULL);
I have also tried opening the file with the 'r' flag instead of 'rb'. I have also trawled google and SO for several hours. All of this to no avail. There is no error and the function does not return NULL, it just exits with code 0. How can I get this to work properly so that I end up with a X509 object?
Well, I still don't know why the PEM_read_x509 function doesn't work, but I believe that I have found a workaround.
X509* openPemFile(char* filename)
{
X509* cert = X509_new();
BIO* bio_cert = BIO_new_file(filename, "rb");
PEM_read_bio_X509(bio_cert, &cert, NULL, NULL);
return cert;
}
This returns a certificate that I can get data from. The two main differences are the initializing of cert with a new() call, and the use of the PEM_read_bio_X509 function. I'm not sure why, but this gives me a useable certificate object. I tried the pervious function, the PEM_read_X509, and it did not work, even with the initialized object.
Those reading functions have some rules about how they use the passed pointer-to-pointer argument:
If x is NULL then the parameter is ignored. If x is not NULL but *x is
NULL then the structure returned will be written to *x. If neither x
nor *x is NULL then an attempt is made to reuse the structure at *x
(but see BUGS and EXAMPLES sections). Irrespective of the value of x a
pointer to the structure is always returned (or NULL if an error
occurred).
In you case you have an uninitialized pointer
X509* cert;
which is likely to have some random non-NULL value. You then pass the address of the pointer to the reading function as &cert.
The library sees that x is not NULL (address of your pointer) and *x is not NULL (uninitialized value of the pointer) and so it treats value of *x as a pointer to an existing X509 structure, which is obviously not the case.
There are several ways to fix the problem.
Simply pass NULL instead of &cert to the reading function and use the returned address to initialize the cert value:
X509* cert = PEM_read_X509(certfile, NULL, 0, NULL);
Initialize the value of cert before passing it to the reading function:
X509* cert = NULL;
bool success = PEM_read_X509(certfile, &cert, 0, NULL) != NULL;
Or precreate the X509 structure as you do in your own answer, but note that some versions of OpenSSL may not correctly reuse the existing structure due to bugs.
Conclusion:
Always initialize your variables before usage (ideally at the point of declaration).
RTFM :)

Access Amazon S3 services with C++ GSOAP client

I am starting to develop an app to access the Amazon S3 storage using the SOAP API.
I have read the documents that says the the method PutObject must be used if the file size is greater than 1 MB.
Now PutObject uses DIME attachment.
Is there a sample code or example or a fragment of code that someone can show me on how to do DIME attachement with GSOAP for the PutObject method of Amazon S3.
I want to use GSOAP because of portability and to make it generic. I do not want to use the .NET API provided by Amazon for the same reason. I want in GSOAP particularly as I have worked in GSOAP earlier.
Thanks,
david
I put together something that uploads files larger than 1MB using PutObject, it should also work for smaller files.
I share it for others who might find it useful.
Also see my previous post on using GSOAP to access S3 AMAZON AWS S3 using GSOAP C C++
The link also contains the method to generate the signature.
Here is the code for PutObject.
It uses the latest GSOAP from sourceforge.
After wsdl2h to generate the header and soapcpp2 to generate the gsoap client code the following will be the code to access the service PutObject......
Requirements : OpenSSL GSOAP Build with the compiler preprocessor directive WITH_OPENSSL. Include the library files libeay32 and ssleay32. Take the methods to generate signature from the link above.
void PutObject(char *filename)
{
AmazonS3SoapBindingProxy amazonS3Interface;
struct soap* soapPtr;
soapPtr = dynamic_cast<struct soap*>(&amazonS3Interface);
soap_init2(soapPtr, SOAP_IO_DEFAULT|SOAP_IO_KEEPALIVE, SOAP_IO_DEFAULT|SOAP_IO_KEEPALIVE);
soap_ssl_client_context(&amazonS3Interface,
SOAP_SSL_NO_AUTHENTICATION, /* for encryption w/o authentication */
/* SOAP_SSL_DEFAULT | SOAP_SSL_SKIP_HOST_CHECK, */ /* if we don't want the host name checks since these will change from machine to machine */
/*SOAP_SSL_DEFAULT,*/ /* use SOAP_SSL_DEFAULT in production code */
NULL, /* keyfile (cert+key): required only when client must authenticate to server (see SSL docs to create this file) */
NULL, /* password to read the keyfile */
NULL, /* optional cacert file to store trusted certificates, use cacerts.pem for all public certificates issued by common CAs */
NULL, /* optional capath to directory with trusted certificates */
NULL /* if randfile!=NULL: use a file with random data to seed randomness */
);
//use this if you are behind a proxy to connect to internet
amazonS3Interface.proxy_host="proxyservername"; //proxyservername
amazonS3Interface.proxy_port=4050; //proxy port
amazonS3Interface.proxy_userid="username"; //proxy authentication
amazonS3Interface.proxy_passwd="password";
amazonS3Interface.proxy_http_version="1.1"; //http ver
amazonS3Interface.dime_id_format ="uuid:09233523-345b-4351-b623-5dsf35sgs5d6-%x";
// Set callback functions
soapPtr->fdimereadopen = dime_read_open;
soapPtr->fdimereadclose = dime_read_close;
soapPtr->fdimeread =dime_read;
_ns1__PutObject preq;
_ns1__PutObjectResponse presp;
ns1__PutObjectResult res;
FILE *fp=fopen(filename,"rb");
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
preq.Bucket=std::string("FGTSDrive");//bucket name to put file in
preq.AWSAccessKeyId=new std::string("ACCESSKEY");//access key here
char *sig=aws_signature("SECRETKEY","AmazonS3","PutObject",xml_datetime(),NULL);//correct secretkey here
preq.Signature=new std::string(sig);
preq.Timestamp=new time_t(time(NULL));
preq.Key=std::string(filename);//name of the key ie the filename
int result(0);
preq.ContentLength=sz; //length of the file
ns1__MetadataEntry med;
med.Name=std::string("Content-Type");
med.Value=std::string("application/zip");//change the type depending on the file extenstion
med.soap=&amazonS3Interface;
preq.Metadata.push_back(&med);
soap_set_dime(soapPtr);
result =soap_set_dime_attachment(soapPtr, (char*)fp, sz,"application/zip", NULL, 0,filename);//change the content type depending on the file extenstion
if (result != SOAP_OK) { }
result = amazonS3Interface.PutObject(&preq, &presp);
if (result != SOAP_OK) { }
amazonS3Interface.soap_stream_fault(std::cout);
}
static void *dime_read_open(struct soap *soap, void *handle, const char *id, const char *type, const char *options)
{ // we should return NULL without setting soap->error if we don't want to use the streaming callback for this DIME attachment. The handle contains the non-NULL __ptr field value which should have been set in the application.
// return value of this function will be passed on to the fdimeread and fdimereadclose callbacks. The return value will not affect the __ptr field.
std::cout <<"dime_read_open"<<std::endl;
return handle;
}
static void dime_read_close(struct soap *soap, void *handle)
{
std::cout <<"dime_read_close"<<std::endl;
fclose((FILE*)handle);
}
static size_t dime_read(struct soap *soap, void *handle, char *buf, size_t len)
{
std::cout <<"dime_read_read"<<std::endl;
return fread(buf, 1, len, (FILE*)handle);
}
Hope it helps.
Thanks,
david