📄 wsseapi.c
字号:
Alternatively, a DOM can be used to store and retrieve XML tokens:@code#import "dom.h"typedef struct _wsse__Security{ struct _wsu__Timestamp* wsu__Timestamp; struct _wsse__UsernameToken* UsernameToken; struct _wsse__BinarySecurityToken* BinarySecurityToken; struct ds__SignatureType* ds__Signature; int __size; xsd__anyType* any; @char* SOAP_ENV__actor; @char* SOAP_ENV__role;} _wsse__Security;@endcode@section wsse_7 Token ReferencesThe material in this section relates to the WS-Security specification section 7.To use a certificate for signature verification, add a direct security tokenreference URI for the token to the KeyInfo, for example:@code soap_wsse_add_KeyInfo_SecurityTokenReferenceURI(soap, "URI", "valueType");@endcodeand:@code soap_wsse_add_KeyInfo_SecurityTokenReferenceX509(soap, "URI");@endcodeFor X509 certificates we use this to add a binary security token with thecertificate and a reference to the local token:@code if (soap_wsse_add_BinarySecurityTokenX509(soap, "X509Token", cert) || soap_wsse_add_KeyInfo_SecurityTokenReferenceX509(soap, "#X509Token")) ... // an error occurred@endcodeThis follows the recommended practice to place Security token references inthe KeyInfo element of a Signature. The KeyInfo is used to verify the validityof a signature value.Key identifiers can be used as well:@code soap_wsse_add_KeyInfo_SecurityTokenReferenceKeyIdentifier(soap, "Id", "valueType", data, datalen);@endcodeEmbedded references are added with:@code soap_wsse_add_KeyInfo_SecurityTokenReferenceEmbedded(soap, "Id", "valueType");@endcodeFull support for embedded references requires coding to add tokens andassertions, as well as to consume embedded references at the receiving side.There is no automated mechanism to take the embedded references and processthem accordingly.The use of key names is not recommended, but in case they are required they canbe added with:@code soap_wsse_add_KeyInfo_KeyName(soap, "name");@endcode@section wsse_8 SignaturesThe material in this section relates to the WS-Security specification section 8.The wsse plugin must be registered to sign and verify messages:@code soap_register_plugin(soap, soap_wsse);@endcodeXML signatures are usually computed over normalized XML (to ensure the XMLprocessors of intermediate nodes can accurately reproduce the XML). To thisend, the exclusive canonical XML standard (exc-c14n) is required, which is setusing the SOAP_XML_CANONICAL flag:@code struct soap *soap = soap_new1(SOAP_XML_CANONICAL); soap_register_plugin(soap, soap_wsse);@endcodeIf you prefer XML indentation, use:@code struct soap *soap = soap_new1(SOAP_XML_CANONICAL | SOAP_XML_INDENT); soap_register_plugin(soap, soap_wsse);@endcodeNext, we decide which signature algorithm is appropriate to use:- HMAC-SHA1 uses a secret key (also known as a shared key in symmetric cryptography) to sign the SHA1 digest of the SignedInfo element.- DSA-SHA1 uses a DSA private key to sign the SHA1 digest of the SignedInfo element.- RSA-SHA1 uses a RSA private key to sign the SHA1 digest of the SignedInfo element.HMAC-SHA1 is the simplest method, but relies on the fact that you have to makeabsolutely sure the key is kept secret on both the sending and receiving side.As long as the secret key is confidential, messages are securely signed.However, this is virtually impossible when exchanging messages with untrusteddisparate parties. The advantage of HMAC-SHA1 is the speed by which messagesare signed and verified.DSA-SHA1 and RSA-SHA1 rely on public key cryptography. In simplified terms, amessage is signed using the (confidential!) private key. The public key is usedto verify the signature. Since only the originating party could have used itsprivate key to sign the message, the integrity of the message is guaranteed. Ofcourse, we must trust the public key came from the originator (it is oftenincluded as an X509 certificate in the message). To this end, a trustedcertificate authority should have signed the public key, thereby creating aX509 certificate that contains the public key and the identity of the messageoriginator.@subsection wsse_8_2a Signing MessagesAfter the plugin is registered and a signature algorithm selected, the@ref soap_wsse_sign function or the @ref soap_wsse_sign_body function is usedto initiate the signature engine to automatically sign outbound messages.The code to sign the SOAP Body of a message using HMAC-SHA1 is:@code static char hmac_key[16] = { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00 }; struct soap *soap = soap_new1(SOAP_XML_CANONICAL | SOAP_XML_INDENT); soap_register_plugin(soap, soap_wsse); if (soap_wsse_sign_body(soap, SOAP_SMD_HMAC_SHA1, hmac_key, sizeof(hmac_key)) ... // an error occurred else if (soap_call_ns__myMethod(soap, ...)) ... // a transmission error occurred@endcodeThe hmac_key is some secret key you generated for the sending side andreceiving side (don't use the one shown here).As always, use @ref soap_print_fault to display the error message.To sign the body of an outbound SOAP message using RSA-SHA1 (DSA-SHA1 issimilar), we include the X509 certificate with the public key as aBinarySecurityToken in the header and a KeyInfo reference to the token to letreceivers use the public key in the certificate to verify the authenticity ofthe message:@code FILE *fd; EVP_PKEY *rsa_private_key; X509 *cert; struct soap *soap = soap_new1(SOAP_XML_CANONICAL | SOAP_XML_INDENT); soap_register_plugin(soap, soap_wsse); fd = fopen("privkey.pem", "r"); rsa_private_key = PEM_read_PrivateKey(fd, NULL, NULL, "password"); fclose(fd); fd = fopen("cert.pem", "r"); X509 *cert = PEM_read_X509(fd, NULL, NULL, NULL); fclose(fd); if (soap_wsse_add_BinarySecurityTokenX509(soap, "X509Token", cert) || soap_wsse_add_KeyInfo_SecurityTokenReferenceX509(soap, "#X509Token") || soap_wsse_sign_body(soap, SOAP_SMD_SIGN_RSA_SHA1, rsa_private_key, 0)) ... // an error occurred else if (soap_call_ns__myMethod(soap, ...)) ... // a transmission error occurred@endcodeThe private key and its certificate are often placed in the same file, see e.g.server.pem in the package.To summarize the signing process:-# Register the wsse plugin.-# Obtain an HMAC secret key or a DSA or RSA private key.-# For DSA or RSA, obtain the X509 certificate with the public key signed by a certificate authority.-# Add the X509 certificate as a BinarySecurityToken to the header.-# Add a KeyInfo BinarySecurityTokenReference.-# Invoke @ref soap_wsse_sign or @ref soap_wsse_sign_body to sign the message.-# Always check the function return values for errors. You don't want to produce and accept messages with an invalid Security headers.@subsection wsse_8_2b Signing Message PartsThe @ref soap_wsse_sign_body function signs the entire SOAP body. If it isdesirable to sign individual parts of a message the @ref soap_wsse_signfunction should be used. Message parts with wsu:Id attributes are signed. Thesemessage parts should not be nested (nested elements will not be separatelysigned).For example, consider a transaction in which we only want to sign a contract inthe SOAP Body. This allows us to modify the rest of the message or extract thecontract in XML and pass it on with the signature.The gSOAP header file includes a myContract declaration:@code struct ns__myContract { @char* wsu_Id = "Contract"; char* name; char* title; char* terms; }; int ns__myMethod(struct ns__myContract agreement, bool* accepted);@endcodeThe default value of the wsu:Id is "Contract" so that we can instantiate thestruct, automatically sign it, and send it as follows:@code struct ns__myContract contract; bool accept; soap_default_ns__myContract(soap, &contract); contract.name = ...; contract.title = ...; contract.terms = ...; if (soap_wsse_add_BinarySecurityTokenX509(soap, "X509Token", cert) || soap_wsse_add_KeyInfo_SecurityTokenReferenceX509(soap, "#X509Token") || soap_wsse_sign(soap, SOAP_SMD_SIGN_RSA_SHA1, rsa_private_key, 0)) ... // an error occurred else if (soap_call_ns__myMethod(soap, contract, &accept)) ... // a transmission error occurred@endcode@subsection wsse_8_3 Signing TokensTo sign security tokens such as user names, passwords, and binary securitytokens, just assign their Id values with a unique string, such as "Time" fortimestamps and "User" for user names. For example:@code soap_wsse_add_Timestamp(soap, "Time", 600); soap_wsse_add_UsernameTokenDigest(soap, "User", "username", "password"); ... // the rest of the signing code@endcode@subsection wsse_8_4 Signature ValidationTo automatically verify the signature of an inbound message signed with DSA orRSA algorithms, assuming the message contains the X509 certificate as a binarysecurity token, use:@code struct soap *soap = soap_new1(SOAP_XML_CANONICAL | SOAP_XML_INDENT); soap_register_plugin(soap, soap_wsse); soap_wsse_verify_auto(soap, SOAP_SMD_NONE, NULL, 0); // server: if (soap_serve(soap)) ... // an error occurred // client: if (soap_call_ns__myMethod(soap, ...)) ... // an error occurred@endcodeAll locally referenced elements in the signed message will be verified.Elements referenced with absolute URIs are not automatically verified. Thereceived message is stored in a DOM accessible with soap->dom. This enablesfurther analysis of the message content.The @ref soap_wsse_verify_auto function keeps processing signed (and unsigned)messages as they arrive. For unsigned messages this can be expensive and theverification engine should be shut down using @ref soap_wsse_verify_done.To verify the HMAC signature of an inbound message, the HMAC key must besupplied:@code static char hmac_key[16] = // the same secret key that was used to sign { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00 }; struct soap *soap = soap_new1(SOAP_XML_CANONICAL | SOAP_XML_INDENT); soap_register_plugin(soap, soap_wsse); soap_wsse_verify_auto(soap, SOAP_SMD_HMAC_SHA1, hmac_key, sizeof(hmac_key)); // server: if (soap_serve(soap)) ... // an error occurred // client: if (soap_call_ns__myMethod(soap, ...)) ... // an error occurred@endcodeTo summarize the signature verification process:-# Register the wsse plugin.-# For HMAC, obtain the HMAC secret key-# Use @ref soap_wsse_verify_auto to verify inbound messages.-# After receiving a message, the DOM in soap->dom can be traversed for further analysis.-# Always check the function return values for errors. You don't want to accept a request or response message with an invalid Security header.-# Use @ref soap_wsse_verify_done to terminate verification, e.g. to consume plain messages more efficiently.@section wsse_9 EncryptionThe material in this section relates to the WS-Security specification section 9.TODO item: encryption support is under construction.@section wsse_10 Security TimestampsThe material in this section relates to the WS-Security specification section10.To add a timestamp with the creation time to the Security header, use:@code soap_wsse_add_Timestamp(soap, NULL, 0); // no expiration@endcodeThe lifetime of a message (in seconds) is passed as the third argument, whichwill be displayed as the timestamp expiration time:@code
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -