diff --git a/CHANGES.md b/CHANGES.md index 97b86158fc..8b4de2be88 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ Release 5.0.0 (Next release) Features -------- +* [#915](https://github.com/java-native-access/jna/pull/915): Adding interfaces to call to Cryptui and Crypt32 windows libraries and adding related structures to Wincrypt. - [@rosh89](https://github.com/rosh89). * [#903](https://github.com/java-native-access/jna/pull/903): Carry `HRESULT` in `c.s.j.p.win32.COM.COMException`, introduce `c.s.j.p.win32.COM.COMInvokeException` as subclass of `COMException` for exception as the result of a `IDispatch#Invoke`. The `EXECPINFO` is unwrapped into fields in the `COMInvokeException` and correctly freed. - [@matthiasblaesing](https://github.com/matthiasblaesing). * [#822](https://github.com/java-native-access/jna/issues/822): `Native#loadLibrary` requires that the interface class passed in is an instance of Library. The runtime check can be enhanced by using a constraint generic. This breaks binary compatibility (see notes below) - [@d-noll](https://github.com/d-noll). * [#889](https://github.com/java-native-access/jna/issues/889): The `Structure#newInstance` receive the target type as a parameter. This adds a limited generic type, so that the return type ist the target type and not a generic structure, removing the necessity to do an explizit cast - [@matthiasblaesing](https://github.com/matthiasblaesing). diff --git a/contrib/platform/nbproject/project.properties b/contrib/platform/nbproject/project.properties index 2f595eea00..119204a4ec 100644 --- a/contrib/platform/nbproject/project.properties +++ b/contrib/platform/nbproject/project.properties @@ -48,7 +48,7 @@ jar.compress=false javac.classpath=\ ${file.reference.jna.jar} # Space-separated list of extra javac options -javac.compilerargs= +javac.compilerargs=-XDignore.symbol.file javac.deprecation=false javac.source=1.6 javac.target=1.6 diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Crypt32.java b/contrib/platform/src/com/sun/jna/platform/win32/Crypt32.java index 204f8f1d94..cdd92bca46 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Crypt32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Crypt32.java @@ -30,6 +30,10 @@ import com.sun.jna.ptr.PointerByReference; import com.sun.jna.win32.StdCallLibrary; import com.sun.jna.win32.W32APIOptions; +import com.sun.jna.platform.win32.WinCrypt.*; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.platform.win32.WinBase.FILETIME; +import com.sun.jna.platform.win32.WTypes.LPSTR; /** * Crypt32.dll Interface. @@ -140,6 +144,351 @@ public boolean CryptUnprotectData(DATA_BLOB pDataIn, PointerByReference szDataDe * handling behaviors.
* For extended error information, call GetLastError. * @see MSDN - */ - boolean CertAddEncodedCertificateToSystemStore(String szCertStoreName, Pointer pbCertEncoded, int cbCertEncoded); + */ + boolean CertAddEncodedCertificateToSystemStore(String szCertStoreName, Pointer pbCertEncoded, int cbCertEncoded); + + /** + * The CertOpenSystemStore function is a simplified function that opens the + * most common system certificate store. To open certificate stores with + * more complex requirements, such as file-based or memory-based stores, use + * CertOpenStore. + * + * @param hprov This parameter is not used and should be set to NULL. + * @param szSubsystemProtocol A string that names a system store. If the + * system store name provided in this parameter is not the name of an + * existing system store, a new system store will be created and used. + * CertEnumSystemStore can be used to list the names of existing system + * stores. Some example system stores are listed in the following table. + * @return If the function succeeds, the function returns a handle to the + * certificate store. If the function fails, it returns NULL. For extended + * error information, call GetLastError. + */ + HCERTSTORE CertOpenSystemStore(Pointer hprov, String szSubsystemProtocol); + + /** + * The CryptSignMessage function creates a hash of the specified content, + * signs the hash, and then encodes both the original message content and + * the signed hash. + * + * @param pSignPara A pointer to CRYPT_SIGN_MESSAGE_PARA structure + * containing the signature parameters. + * @param fDetachedSignature TRUE if this is to be a detached signature. + * Otherwise, FALSE. If this parameter is set to TRUE, only the signed hash + * is encoded in pbSignedBlob. Otherwise, both rgpbToBeSigned and the signed + * hash are encoded. + * @param cToBeSigned Count of the number of array elements in + * rgpbToBeSigned and rgpbToBeSigned. This parameter must be set to one + * unless fDetachedSignature is set to TRUE. + * @param rgpbToBeSigned Array of pointers to buffers that contain the + * contents to be signed. + * @param rgcbToBeSigned Array of sizes, in bytes, of the content buffers + * pointed to in rgpbToBeSigned. + * @param pbSignedBlob A pointer to a buffer to receive the encoded signed + * hash, if fDetachedSignature is TRUE, or to both the encoded content and + * signed hash if fDetachedSignature is FALSE. + * @param pcbSignedBlob A pointer to a DWORD specifying the size, in bytes, + * of the pbSignedBlob buffer. When the function returns, this variable + * contains the size, in bytes, of the signed and encoded message. + * @return If the function succeeds, the return value is nonzero (TRUE). If + * the function fails, the return value is zero (FALSE). + */ + boolean CryptSignMessage(CRYPT_SIGN_MESSAGE_PARA pSignPara, boolean fDetachedSignature, int cToBeSigned, + Pointer[] rgpbToBeSigned, int[] rgcbToBeSigned, Pointer pbSignedBlob, IntByReference pcbSignedBlob); + + /** + * The CryptVerifyMessageSignature function verifies a signed message's + * signature. + * + * This function should not be used to verify the signature of a detached + * message. You should use the CryptVerifyDetachedMessageSignature function + * to verify the signature of a detached message. + * + * @param pVerifyPara A pointer to a CRYPT_VERIFY_MESSAGE_PARA structure + * that contains verification parameters. + * @param signerIndex The index of the de sired signature. There can be more + * than one signature. CryptVerifyMessageSignature can be called repeatedly, + * incrementing dwSignerIndex each time. + * + *

+ * Set this pa rameter to zero for the first signer, or if there is only one + * signer. If the function returns FALSE, and GetLastError returns + * CRYPT_E_NO_SIGNER, the previous call processed the last signer of the + * message.

+ * @param pbSignedBlob A pointer to a buffe r that contains the signed + * message. + * @param cbSignedBlob The size, in bytes, of the signed message buffer. + * @param pbDecoded * A pointer to a buffer to receive the decoded message. + * + *

+ * This parameter can be NULL if the decoded message is not needed for + * additional processing or to set the size of the message for memory + * allocation purposes. For more information, see Retrieving Data of Unknown + * Length.

+ * + * @param pcbDecoded A pointer to a DWO RD value that specifies the size, in + * bytes, of the pbDecoded buffer. When the function returns, this DWORD + * contains the size, in bytes, of the decoded message. The decoded message + * will not be returned if this parameter is NULL. + * @param ppSignerCert The address of a CER T_CONTEXT structure pointer that + * receives the certificate of the signer. When you have finished using this + * structure, free it by passing this pointer to the + * CertFreeCertificateContext function. This parameter can be NULL if the + * signer's certificate is not needed. + * @return If the function succeeds, the function returns nonzero. This does + * not necessarily mean that the signature was verified. In the case of a + * detached message, the variable pointe d to by pcbDecoded will contain + * zero. In this case, this funct ion will return nonzero, but the signature + * is not verified . To verify the signature of a detached message, use the + * CryptVerifyDetachedMessageSignature function. + * + *

+ * If the function succeeds, the function returns nonzero. This does not + * necessarily mean that the signature was verified. In the case of a + * detached message, the variable pointed to by pcbDecoded will contain + * zero. In this case, this function will return nonzero, but the signature + * is not verified. To verify the signature of a detached message, use t he + * CryptVerifyDetachedMessageSignature function. + */ + boolean CryptVerifyMessageSignature(CRYPT_VERIFY_MESSAGE_PARA pVerifyPara, + int signerIndex, Pointer pbSignedBlob, int cbSignedBlob, + Pointer pbDecoded, IntByReference pcbDecoded, PointerByReference ppSignerCert); + + /** + * The CertGetCertificateChain function builds a certificate chain context + * starting from an end certificate and going back, if possible, to a + * trusted root certificate. + * + * @param hChainEngine A handle of the chain engine (namespace and cache) to + * be used. If hChainEngine is NULL, the default chain engine, + * HCCE_CURRENT_USER, is used. This parameter can be set to + * HCCE_LOCAL_MACHINE. + * @param pCertContext A pointer to the CERT_CONTEXT of the end certificate, + * the certificate for which a chain is being built. This certificate + * context will be the zero-index element in the first simple chain. + * @param pTime A pointer to a FILETIME variable that indicates the time for + * which the chain is to be validated. Note that the time does not affect + * trust list, revocation, or root store checking. The current system time + * is used if NULL is passed to this parameter. Trust in a particular + * certificate being a trusted root is based on the current state of the + * root store and not the state of the root store at a time passed in by + * this parameter. For revocation, a certificate revocation list (CRL), + * itself, must be valid at the current time. The value of this parameter is + * used to determine whether a certificate listed in a CRL has been revoked. + * @param hAdditionalStore A handle to any additional store to search for + * supporting certificates and certificate trust lists (CTLs). This + * parameter can be NULL if no additional store is to be searched. + * @param pChainPara A pointer to a CERT_CHAIN_PARA structure that includes + * chain-building parameters. + * @param dwFlags Flag values that indicate special processing. This + * parameter can be a combination of one or more of the following flags. + * @param pvReserved This parameter is reserved and must be NULL. + * @param ppChainContext The address of a pointer to the chain context + * created. When you have finished using the chain context, release the + * chain by calling the CertFreeCertificateChain function. + * @return If the function succeeds, the function returns nonzero (TRUE). If + * the function fails, it returns zero (FALSE). + */ + boolean CertGetCertificateChain(HCERTCHAINENGINE hChainEngine, CERT_CONTEXT pCertContext, FILETIME pTime, + HCERTSTORE hAdditionalStore, CERT_CHAIN_PARA pChainPara, int dwFlags, Pointer pvReserved, + PointerByReference ppChainContext); + + /** + * The CertFreeCertificateContext function frees a certificate context by + * decrementing its reference count. When the reference count goes to zero, + * CertFreeCertificateContext frees the memory used by a certificate + * context. + * + * @param pCertContext A pointer to the CERT_CONTEXT to be freed. + * @return The function always returns nonzero. + */ + boolean CertFreeCertificateContext(CERT_CONTEXT pCertContext); + + /** + * The CertFreeCertificateChain function frees a certificate chain by + * reducing its reference count. If the reference count becomes zero, memory + * allocated for the chain is released. + * + *

To free a context obtained by a get, duplicate, or create function, call + * the appropriate free function. To free a context obtained by a find or + * enumerate function, either pass it in as the previous context parameter + * to a subsequent invocation of the function, or call the appropriate free + * function. For more information, see the reference topic for the function + * that obtains the context.

+ * + * @param pChainContext A pointer to a CERT_CHAIN_CONTEXT certificate chain + * context to be freed. If the reference count on the context reaches zero, + * the storage allocated for the context is freed. + */ + void CertFreeCertificateChain(CERT_CHAIN_CONTEXT pChainContext); + + /** + * The CertCloseStore function closes a certificate store handle and reduces + * the reference count on the store. There needs to be a corresponding call + * to CertCloseStore for each successful call to the CertOpenStore or + * CertDuplicateStore functions. + * + * @param hCertStore Handle of the certificate store to be closed. + * @param dwFlags Typically, this parameter uses the default value zero. The + * default is to close the store with memory remaining allocated for + * contexts that have not been freed. In this case, no check is made to + * determine whether memory for contexts remains allocated. + * @return If the function succeeds, the return value is TRUE. If the + * function fails, the return value is FALSE. + */ + boolean CertCloseStore(HCERTSTORE hCertStore, int dwFlags); + + /** + * The CertNameToStr function converts an encoded name in a CERT_NAME_BLOB + * structure to a character string. + * + * @param dwCertEncodingType The certificate encoding type that was used to + * encode the name. The message encoding type identifier, contained in the + * high WORD of this value, is ignored by this function. + * @param pName A pointer to the CERT_NAME_BLOB structure to be converted. + * @param dwStrType This parameter specifies the format of the output + * string. This parameter also specifies other options for the contents of + * the string. + * @param psz A pointer to a character buffer that receives the returned + * string. The size of this buffer is specified in the csz parameter. + * @param csz The size, in characters, of the psz buffer. The size must + * include the terminating null character. + * @return Returns the number of characters converted, including the + * terminating null character. If psz is NULL or csz is zero, returns the + * required size of the destination string. + */ + int CertNameToStr(int dwCertEncodingType, DATA_BLOB pName, int dwStrType, Pointer psz, int csz); + + /** + * The CertVerifyCertificateChainPolicy function checks a certificate chain + * to verify its validity, including its compliance with any specified + * validity policy criteria. + * + * @param pszPolicyOID Current predefined verify chain policy structures are + * listed in the following table. + * @param pChainContext A pointer to a CERT_CHAIN_CONTEXT structure that + * contains a chain to be verified. + * @param pPolicyPara A pointer to a CERT_CHAIN_POLICY_PARA structure that + * provides the policy verification criteria for the chain. The dwFlags + * member of that structure can be set to change the default policy checking + * behavior. + * @param pPolicyStatus A pointer to a CERT_CHAIN_POLICY_STATUS structure + * where status information on the chain is returned. OID-specific extra + * status can be returned in the pvExtraPolicyStatus member of this + * structure. + * @return The return value indicates whether the function was able to check + * for the policy, it does not indicate whether the policy check failed or + * passed. + * + * If the chain can be verified for the specified policy, TRUE is returned + * and the dwError member of the pPolicyStatus is updated. A dwError of 0 + * (ERROR_SUCCESS or S_OK) indicates the chain satisfies the specified + * policy. + * + * If the chain cannot be validated, the return value is TRUE and you need + * to verify the pPolicyStatus parameter for the actual error. + * + * A value of FALSE indicates that the function wasn't able to check for the + * policy. + */ + boolean CertVerifyCertificateChainPolicy(LPSTR pszPolicyOID, CERT_CHAIN_CONTEXT pChainContext, + CERT_CHAIN_POLICY_PARA pPolicyPara, CERT_CHAIN_POLICY_STATUS pPolicyStatus); + + /** + * The CertFindCertificateInStore function finds the first or next + * certificate context in a certificate store that matches a search criteria + * established by the dwFindType and its associated pvFindPara. This + * function can be used in a loop to find all of the certificates in a + * certificate store that match the specified find criteria. + * + * @param hCertStore A handle of the certificate store to be searched. + * @param dwCertEncodingType Specifies the type of encoding used. Both the + * certificate and message encoding types must be specified by combining + * them with a bitwise-OR. + * @param dwFindFlags Used with some dwFindType values to modify the search + * criteria. For most dwFindType values, dwFindFlags is not used and should + * be set to zero. + * @param dwFindType Specifies the type of search being made. The search + * type determines the data type, contents, and the use of pvFindPara. + * @param pvFindPara Points to a data item or structure used with + * dwFindType. + * @param pPrevCertContext A pointer to the last CERT_CONTEXT structure + * returned by this function. This parameter must be NULL on the first call + * of the function. To find successive certificates meeting the search + * criteria, set pPrevCertContext to the pointer returned by the previous + * call to the function. This function frees the CERT_CONTEXT referenced by + * non-NULL values of this parameter. + * @return If the function succeeds, the function returns a pointer to a + * read-only CERT_CONTEXT structure. + * + * If the function fails and a certificate that matches the search criteria + * is not found, the return value is NULL. + * + * A non-NULL CERT_CONTEXT that CertFindCertificateInStore returns must be + * freed by CertFreeCertificateContext or by being passed as the + * pPrevCertContext parameter on a subsequent call to + * CertFindCertificateInStore. + */ + CERT_CONTEXT.ByReference CertFindCertificateInStore(HCERTSTORE hCertStore, int dwCertEncodingType, int dwFindFlags, + int dwFindType, Pointer pvFindPara, CERT_CONTEXT pPrevCertContext); + + /** + * The PFXImportCertStore function imports a PFX BLOB and returns the handle + * of a store that contains certificates and any associated private keys. + * + * @param pPFX A pointer to a CRYPT_DATA_BLOB structure that contains a PFX + * packet with the exported and encrypted certificates and keys. + * @param szPassword A string password used to decrypt and verify the PFX + * packet. Whether set to a string of length greater than zero or set to an + * empty string or to NULL, this value must be exactly the same as the value + * that was used to encrypt the packet. + * + *

+ * Beginning with Windows 8 and Windows Server 2012, if the PFX packet was + * created in the PFXExportCertStoreEx function by using the + * PKCS12_PROTECT_TO_DOMAIN_SIDS flag, the PFXImportCertStore function + * attempts to decrypt the password by using the Active Directory (AD) + * principal that was used to encrypt it. The AD principal is specified in + * the pvPara parameter. If the szPassword parameter in the + * PFXExportCertStoreEx function was an empty string or NULL and the dwFlags + * parameter was set to PKCS12_PROTECT_TO_DOMAIN_SIDS, that function + * randomly generated a password and encrypted it to the AD principal + * specified in the pvPara parameter. In that case you should set the + * password to the value, empty string or NULL, that was used when the PFX + * packet was created. The PFXImportCertStore function will use the AD + * principal to decrypt the random password, and the randomly generated + * password will be used to decrypt the PFX certificate.

+ * + *

+ * When you have finished using the password, clear it from memory by + * calling the SecureZeroMemory function. For more information about + * protecting passwords, see Handling Passwords.

+ * + * @param dwFlags This parameter can be one of the following values. + * + * + * @return If the function succeeds, the function returns a handle to a + * certificate store that contains the imported certificates, including + * available private keys. + * + *

+ * If the function fails, that is, if the password parameter does not + * contain an exact match with the password used to encrypt the exported + * packet or if there were any other problems decoding the PFX BLOB, the + * function returns NULL, and an error code can be found by calling the + * GetLastError function.

+ * + * @see MSDN + */ + HCERTSTORE PFXImportCertStore(DATA_BLOB pPFX, WTypes.LPWSTR szPassword, int dwFlags); } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java index 0c73a0d05b..d1712ee3b8 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java @@ -23,6 +23,9 @@ */ package com.sun.jna.platform.win32; +import com.sun.jna.Pointer; +import com.sun.jna.Memory; +import com.sun.jna.Native; import com.sun.jna.platform.win32.WinCrypt.CRYPTPROTECT_PROMPTSTRUCT; import com.sun.jna.platform.win32.WinCrypt.DATA_BLOB; import com.sun.jna.ptr.PointerByReference; @@ -174,4 +177,48 @@ public static byte[] cryptUnprotectData(byte[] data, byte[] entropy, int flags, return unProtectedData; } + + /** + * Utility method to call to Crypt32's CertNameToStr that allocates the + * assigns the required memory for the psz parameter based on the type + * mapping used, calls to CertNameToStr, and returns the received string. + * + * @param dwCertEncodingType The certificate encoding type that was used to + * encode the name. The message encoding type identifier, contained in the + * high WORD of this value, is ignored by this function. + * @param pName A pointer to the CERT_NAME_BLOB structure to be converted. + * @param dwStrType This parameter specifies the format of the output + * string. This parameter also specifies other options for the contents of + * the string. + * @return Returns the retrieved string. + */ + public static String CertNameToStr(int dwCertEncodingType, int dwStrType, DATA_BLOB pName) { + int charToBytes = Boolean.getBoolean("w32.ascii") ? 1 : Native.WCHAR_SIZE; + + // Initialize the signature structure. + int requiredSize = Crypt32.INSTANCE.CertNameToStr( + dwCertEncodingType, + pName, + dwStrType, + Pointer.NULL, + 0); + + Memory mem = new Memory(requiredSize * charToBytes); + + // Initialize the signature structure. + int resultBytes = Crypt32.INSTANCE.CertNameToStr( + dwCertEncodingType, + pName, + dwStrType, + mem, + requiredSize); + + assert resultBytes == requiredSize; + + if (Boolean.getBoolean("w32.ascii")) { + return mem.getString(0); + } else { + return mem.getWideString(0); + } + } } \ No newline at end of file diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Cryptui.java b/contrib/platform/src/com/sun/jna/platform/win32/Cryptui.java new file mode 100644 index 0000000000..b2c6f4ea12 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/Cryptui.java @@ -0,0 +1,71 @@ +/* Copyright (c) 2018 Roshan Muralidharan, All Rights Reserved + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.win32; + +import com.sun.jna.Native; +import com.sun.jna.PointerType; +import com.sun.jna.platform.win32.WinDef.HWND; +import com.sun.jna.platform.win32.WinNT.HANDLE; +import com.sun.jna.win32.StdCallLibrary; +import com.sun.jna.win32.W32APIOptions; +import com.sun.jna.platform.win32.WinCrypt.*; + +/** + * Cryptui.dll Interface. + * @author roshan[dot]muralidharan[at]cerner[dot]com + */ +public interface Cryptui extends StdCallLibrary { + + Cryptui INSTANCE = (Cryptui) Native.loadLibrary("Cryptui", Cryptui.class, W32APIOptions.UNICODE_OPTIONS); + + /** + * The CryptUIDlgSelectCertificateFromStore function displays a dialog box that + * allows the selection of a certificate from a specified store. + * + * @param hCertStore + * Handle of the certificate store to be searched. + * @param hwnd + * Handle of the window for the display. If NULL, defaults to the + * desktop window. + * @param pwszTitle + * String used as the title of the dialog box. If NULL, the default + * title, "Select Certificate," is used. + * @param pwszDisplayString + * Text statement in the selection dialog box. If NULL, the default + * phrase, "Select a certificate you want to use," is used. + * @param dwDontUseColumn + * Flags that can be combined to exclude columns of the display. + * @param dwFlags + * Currently not used and should be set to 0. + * @param pvReserved + * Reserved for future use. + * @return Returns a pointer to the selected certificate context. If no + * certificate was selected, NULL is returned. When you have finished + * using the certificate, free the certificate context by calling the + * CertFreeCertificateContext function. + */ + CERT_CONTEXT.ByReference CryptUIDlgSelectCertificateFromStore(HCERTSTORE hCertStore, HWND hwnd, String pwszTitle, + String pwszDisplayString, int dwDontUseColumn, int dwFlags, PointerType pvReserved); + +} diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WTypes.java b/contrib/platform/src/com/sun/jna/platform/win32/WTypes.java index 1ae62a82e5..a36a05d529 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/WTypes.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WTypes.java @@ -179,7 +179,7 @@ public String getString() { } public static class LPSTR extends PointerType { - public static class ByReference extends BSTR implements + public static class ByReference extends LPSTR implements Structure.ByReference { } @@ -192,19 +192,19 @@ public LPSTR(Pointer pointer) { } public LPSTR(String value) { - this(new Memory((value.length() + 1L) * Native.WCHAR_SIZE)); + this(new Memory(value.length() + 1L)); this.setValue(value); } public void setValue(String value) { - this.getPointer().setWideString(0, value); + this.getPointer().setString(0, value); } public String getValue() { Pointer pointer = this.getPointer(); String str = null; if (pointer != null) - str = pointer.getWideString(0); + str = pointer.getString(0); return str; } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinCrypt.java b/contrib/platform/src/com/sun/jna/platform/win32/WinCrypt.java index be61b88397..416959e139 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/WinCrypt.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinCrypt.java @@ -28,9 +28,17 @@ import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; +import com.sun.jna.StringArray; import com.sun.jna.Structure; import com.sun.jna.platform.win32.WinDef.HWND; import com.sun.jna.win32.W32APITypeMapper; +import com.sun.jna.platform.win32.Guid.GUID; +import com.sun.jna.platform.win32.WTypes.LPSTR; +import com.sun.jna.platform.win32.WinBase.FILETIME; +import com.sun.jna.platform.win32.WinCrypt.DATA_BLOB; +import com.sun.jna.platform.win32.WinNT.HANDLE; +import com.sun.jna.Union; +import com.sun.jna.win32.StdCallLibrary; /** * Ported from WinCrypt.h. @@ -43,7 +51,10 @@ public interface WinCrypt { * The CryptoAPI CRYPTOAPI_BLOB structure is used for an arbitrary array of bytes. */ public static class DATA_BLOB extends Structure { + public static class ByReference extends DATA_BLOB implements Structure.ByReference {} + public static final List FIELDS = createFieldsOrder("cbData", "pbData"); + /** * The count of bytes in the buffer pointed to by pbData. */ @@ -87,7 +98,1312 @@ public byte[] getData() { return pbData == null ? null : pbData.getByteArray(0, cbData); } } + + /** + * The CERT_TRUST_STATUS structure contains trust information about a + * certificate in a certificate chain, summary trust information about a + * simple chain of certificates, or summary information about an array of + * simple chains. + * + * @see + * MSDN + */ + public static class CERT_TRUST_STATUS extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwErrorStatus", "dwInfoStatus"); + + public static class ByReference extends CERT_TRUST_STATUS implements Structure.ByReference { + } + + public int dwErrorStatus; + public int dwInfoStatus; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CTL_ENTRY structure is an element of a certificate trust list (CTL). + * + * @see + * MSDN + */ + public static class CTL_ENTRY extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "SubjectIdentifier", "cAttribute", "rgAttribute"); + + public static class ByReference extends CTL_ENTRY implements Structure.ByReference { + } + + public DATA_BLOB SubjectIdentifier; + public int cAttribute; + public Pointer rgAttribute; + + public CRYPT_ATTRIBUTE[] getRgAttribute() { + if (cAttribute == 0) { + return new CRYPT_ATTRIBUTE[0]; + } else { + return (CRYPT_ATTRIBUTE[]) Structure.newInstance( + CERT_EXTENSION.class, + rgAttribute) + .toArray(cAttribute); + } + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * Contains information updated by a certificate revocation list (CRL) + * revocation type handler. The CERT_REVOCATION_CRL_INFO structure is used + * with both base and delta CRLs. + * + * @see + * MSDN + */ + public static class CERT_REVOCATION_CRL_INFO extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "pBaseCRLContext", "pDeltaCRLContext", "pCrlEntry", + "fDeltaCrlEntry"); + + public static class ByReference extends CERT_REVOCATION_CRL_INFO implements Structure.ByReference { + } + + public int cbSize; + public CRL_CONTEXT.ByReference pBaseCRLContext; + public CRL_CONTEXT.ByReference pDeltaCRLContext; + public CRL_ENTRY.ByReference pCrlEntry; + public boolean fDeltaCrlEntry; + + public CERT_REVOCATION_CRL_INFO() { + super(W32APITypeMapper.DEFAULT); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_REVOCATION_INFO structure indicates the revocation status of a + * certificate in a CERT_CHAIN_ELEMENT. + * + * @see + * MSDN + */ + public static class CERT_REVOCATION_INFO extends Structure { + + private static final List fieldOrder = createFieldsOrder("cbSize", + "dwRevocationResult", "pszRevocationOid", "pvOidSpecificInfo", + "fHasFreshnessTime", "dwFreshnessTime", "pCrlInfo"); + + public static class ByReference extends CERT_REVOCATION_INFO implements Structure.ByReference { + } + + public int cbSize; + public int dwRevocationResult; + public String pszRevocationOid; + public Pointer pvOidSpecificInfo; + public boolean fHasFreshnessTime; + public int dwFreshnessTime; + public CERT_REVOCATION_CRL_INFO.ByReference pCrlInfo; + + public CERT_REVOCATION_INFO() { + super(W32APITypeMapper.ASCII); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_CHAIN_ELEMENT structure is a single element in a simple + * certificate chain. Each element has a pointer to a certificate context, a + * pointer to a structure that indicates the error status and information + * status of the certificate, and a pointer to a structure that indicates + * the revocation status of the certificate. + * + * @see + * MSDN + */ + public static class CERT_CHAIN_ELEMENT extends Structure { + + private static final List fieldOrder = createFieldsOrder("cbSize", + "pCertContext", "TrustStatus", "pRevocationInfo", "pIssuanceUsage", + "pApplicationUsage", "pwszExtendedErrorInfo"); + + public static class ByReference extends CERT_CHAIN_ELEMENT implements Structure.ByReference { + } + + public int cbSize; + public CERT_CONTEXT.ByReference pCertContext; + public CERT_TRUST_STATUS TrustStatus; + public CERT_REVOCATION_INFO.ByReference pRevocationInfo; + public CTL_USAGE.ByReference pIssuanceUsage; + public CTL_USAGE.ByReference pApplicationUsage; + + public String pwszExtendedErrorInfo; + + public CERT_CHAIN_ELEMENT() { + super(W32APITypeMapper.UNICODE); + } + + public CERT_CHAIN_ELEMENT(Pointer p) { + super(p, Structure.ALIGN_DEFAULT, W32APITypeMapper.UNICODE); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CTL_INFO structure contains the information stored in a Certificate + * Trust List (CTL). + * + * @see + * MSDN + */ + public static class CTL_INFO extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwVersion", "SubjectUsage", "ListIdentifier", "SequenceNumber", + "ThisUpdate", "NextUpdate", "SubjectAlgorithm", "cCTLEntry", + "rgCTLEntry", "cExtension", "rgExtension"); + + public static class ByReference extends CTL_INFO implements Structure.ByReference { + } + + public int dwVersion; + public CTL_USAGE SubjectUsage; + public DATA_BLOB ListIdentifier; + public DATA_BLOB SequenceNumber; + public FILETIME ThisUpdate; + public FILETIME NextUpdate; + public CRYPT_ALGORITHM_IDENTIFIER SubjectAlgorithm; + public int cCTLEntry; + public Pointer rgCTLEntry; + public int cExtension; + public Pointer rgExtension; + + public CTL_ENTRY[] getRgExtension() { + if (cCTLEntry == 0) { + return new CTL_ENTRY[0]; + } else { + return (CTL_ENTRY[]) Structure.newInstance( + CTL_ENTRY.class, + rgCTLEntry) + .toArray(cCTLEntry); + } + } + + public CERT_EXTENSION[] getRgCTLEntry() { + if (cExtension == 0) { + return new CERT_EXTENSION[0]; + } else { + return (CERT_EXTENSION[]) Structure.newInstance( + CERT_EXTENSION.class, + rgExtension) + .toArray(cExtension); + } + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CTL_CONTEXT structure contains both the encoded and decoded + * representations of a CTL. It also contains an opened HCRYPTMSG handle to + * the decoded, cryptographically signed message containing the CTL_INFO as + * its inner content. + * + * @see + * MSDN + */ + public static class CTL_CONTEXT extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwMsgAndCertEncodingType", "pbCtlEncoded", "cbCtlEncoded", + "pCtlInfo", "hCertStore", "hCryptMsg", "pbCtlContent", + "cbCtlContent"); + + public static class ByReference extends CTL_CONTEXT implements Structure.ByReference { + } + + public int dwMsgAndCertEncodingType; + public Pointer pbCtlEncoded; + public int cbCtlEncoded; + public CTL_INFO.ByReference pCtlInfo; + public HCERTSTORE hCertStore; + public HCRYPTMSG hCryptMsg; + public Pointer pbCtlContent; + public int cbCtlContent; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_TRUST_LIST_INFO structure that indicates valid usage of a CTL. + * + * @see + * MSDN + */ + public static class CERT_TRUST_LIST_INFO extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "pCtlEntry", "pCtlContext"); + + public static class ByReference extends CERT_TRUST_LIST_INFO implements Structure.ByReference { + } + + public int cbSize; + public CTL_ENTRY.ByReference pCtlEntry; + public CTL_CONTEXT.ByReference pCtlContext; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CTL_USAGE structure contains an array of object identifiers (OIDs) + * for Certificate Trust List (CTL) extensions. CTL_USAGE structures are + * used in functions that search for CTLs for specific uses. + * + * @see + * MSDN + */ + public static class CTL_USAGE extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cUsageIdentifier", "rgpszUsageIdentifier"); + + public static class ByReference extends CTL_USAGE implements Structure.ByReference { + } + + public int cUsageIdentifier; + public Pointer rgpszUsageIdentifier; + + public CTL_USAGE() { + super(); + } + + public String[] getRgpszUsageIdentier() { + if (cUsageIdentifier == 0) { + return new String[0]; + } else { + return rgpszUsageIdentifier.getStringArray(0, cUsageIdentifier); + } + } + + public void setRgpszUsageIdentier(String[] array) { + if (array == null || array.length == 0) { + cUsageIdentifier = 0; + rgpszUsageIdentifier = null; + } else { + cUsageIdentifier = array.length; + rgpszUsageIdentifier = new StringArray(array); + } + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_USAGE_MATCH structure provides criteria for identifying issuer + * certificates to be used to build a certificate chain. + * + * @see + * MSDN + */ + public static class CERT_USAGE_MATCH extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwType", "Usage"); + + public static class ByReference extends CERT_USAGE_MATCH implements Structure.ByReference { + } + + public int dwType; + public CTL_USAGE Usage; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_CHAIN_PARA structure establishes the searching and matching + * criteria to be used in building a certificate chain. + * + * @see + * MSDN + */ + public static class CERT_CHAIN_PARA extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "RequestedUsage", "RequestedIssuancePolicy", + "dwUrlRetrievalTimeout", "fCheckRevocationFreshnessTime", + "dwRevocationFreshnessTime", "pftCacheResync", "pStrongSignPara", + "dwStrongSignFlags"); + + public static class ByReference extends CERT_CHAIN_PARA implements Structure.ByReference { + } + + public int cbSize; + public CERT_USAGE_MATCH RequestedUsage; + public CERT_USAGE_MATCH RequestedIssuancePolicy; + public int dwUrlRetrievalTimeout; + public boolean fCheckRevocationFreshnessTime; + public int dwRevocationFreshnessTime; + public FILETIME.ByReference pftCacheResync; + public CERT_STRONG_SIGN_PARA.ByReference pStrongSignPara; + public int dwStrongSignFlags; + + public CERT_CHAIN_PARA() { + super(W32APITypeMapper.DEFAULT); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * Contains parameters used to check for strong signatures on certificates, + * certificate revocation lists (CRLs), online certificate status protocol + * (OCSP) responses, and PKCS #7 messages. + * + * @see + * MSDN + */ + public static class CERT_STRONG_SIGN_PARA extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "dwInfoChoice", "DUMMYUNIONNAME"); + + public static class ByReference extends CERT_CHAIN_PARA implements Structure.ByReference { + } + + public int cbSize; + public int dwInfoChoice; + public DUMMYUNION DUMMYUNIONNAME; + + public class DUMMYUNION extends Union { + + Pointer pvInfo; + CERT_STRONG_SIGN_SERIALIZED_INFO.ByReference pSerializedInfo; + LPSTR pszOID; + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * Contains the signature algorithm/hash algorithm and public key + * algorithm/bit length pairs that can be used for strong signing. This + * structure is used by the CERT_STRONG_SIGN_PARA structure. + * + * @see + * MSDN + */ + public static class CERT_STRONG_SIGN_SERIALIZED_INFO extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwFlags", "pwszCNGSignHashAlgids", "pwszCNGPubKeyMinBitLengths"); + + public static class ByReference extends CERT_CHAIN_PARA implements Structure.ByReference { + } + + public int dwFlags; + public String pwszCNGSignHashAlgids; + public String pwszCNGPubKeyMinBitLengths; + + public CERT_STRONG_SIGN_SERIALIZED_INFO() { + super(W32APITypeMapper.UNICODE); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_CHAIN_POLICY_STATUS structure holds certificate chain status + * information returned by the CertVerifyCertificateChainPolicy function + * when the certificate chains are validated. + * + * @see + * MSDN + */ + public static class CERT_CHAIN_POLICY_STATUS extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "dwError", "lChainIndex", "lElementIndex", + "pvExtraPolicyStatus"); + + public static class ByReference extends CERT_CHAIN_POLICY_STATUS implements Structure.ByReference { + } + + public int cbSize; + public int dwError; + public int lChainIndex; + public int lElementIndex; + public Pointer pvExtraPolicyStatus; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_SIMPLE_CHAIN structure contains an array of chain elements and a + * summary trust status for the chain that the array represents. + * + * @see + * MSDN + */ + public static class CERT_SIMPLE_CHAIN extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "TrustStatus", "cElement", "rgpElement", "pTrustListInfo", + "fHasRevocationFreshnessTime", "dwRevocationFreshnessTime"); + + public static class ByReference extends CERT_SIMPLE_CHAIN implements Structure.ByReference { + } + + public int cbSize; + public CERT_TRUST_STATUS TrustStatus; + public int cElement; + public Pointer rgpElement; + public CERT_TRUST_LIST_INFO.ByReference pTrustListInfo; + + public boolean fHasRevocationFreshnessTime; + public int dwRevocationFreshnessTime; + + public CERT_SIMPLE_CHAIN() { + super(W32APITypeMapper.DEFAULT); + } + + public CERT_CHAIN_ELEMENT[] getRgpElement() { + CERT_CHAIN_ELEMENT[] elements = new CERT_CHAIN_ELEMENT[cElement]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CERT_CHAIN_ELEMENT.class, + rgpElement.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_CHAIN_POLICY_PARA structure contains information used in + * CertVerifyCertificateChainPolicy to establish policy criteria for the + * verification of certificate chains. + * + * @see + * MSDN + */ + public static class CERT_CHAIN_POLICY_PARA extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "dwFlags", "pvExtraPolicyPara"); + + public static class ByReference extends CERT_CHAIN_POLICY_PARA implements Structure.ByReference { + } + + public int cbSize; + public int dwFlags; + public Pointer pvExtraPolicyPara; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_CHAIN_CONTEXT structure contains an array of simple certificate + * chains and a trust status structure that indicates summary validity data + * on all of the connected simple chains. + * + * @see + * MSDN + */ + public static class CERT_CHAIN_CONTEXT extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "TrustStatus", "cChain", "rgpChain", + "cLowerQualityChainContext", "rgpLowerQualityChainContext", + "fHasRevocationFreshnessTime", "dwRevocationFreshnessTime", + "dwCreateFlags", "ChainId"); + + public static class ByReference extends CERT_CHAIN_CONTEXT implements Structure.ByReference { + } + + public int cbSize; + public CERT_TRUST_STATUS TrustStatus; + public int cChain; + public Pointer rgpChain; + public int cLowerQualityChainContext; + public Pointer rgpLowerQualityChainContext; + public boolean fHasRevocationFreshnessTime; + public int dwRevocationFreshnessTime; + public int dwCreateFlags; + public GUID ChainId; + + public CERT_SIMPLE_CHAIN[] getRgpChain() { + CERT_SIMPLE_CHAIN[] elements = new CERT_SIMPLE_CHAIN[cChain]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CERT_SIMPLE_CHAIN.class, + rgpChain.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + public CERT_CHAIN_CONTEXT[] getRgpLowerQualityChainContext() { + CERT_CHAIN_CONTEXT[] elements = new CERT_CHAIN_CONTEXT[cLowerQualityChainContext]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CERT_CHAIN_CONTEXT.class, + rgpLowerQualityChainContext.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + public CERT_CHAIN_CONTEXT() { + super(W32APITypeMapper.DEFAULT); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_CONTEXT structure contains both the encoded and decoded + * representations of a certificate. A certificate context returned by one + * of the functions defined in Wincrypt.h must be freed by calling the + * CertFreeCertificateContext function. The CertDuplicateCertificateContext + * function can be called to make a duplicate copy (which also must be freed + * by calling CertFreeCertificateContext). + * + * @see + * MSDN + */ + public static class CERT_CONTEXT extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwCertEncodingType", "pbCertEncoded", "cbCertEncoded", + "pCertInfo", "hCertStore"); + + public static class ByReference extends CERT_CONTEXT implements Structure.ByReference { + } + + public int dwCertEncodingType; + public Pointer pbCertEncoded; + public int cbCertEncoded; + public CERT_INFO.ByReference pCertInfo; + public HCERTSTORE hCertStore; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_EXTENSION structure contains the extension information for a + * certificate, Certificate Revocation List (CRL) or Certificate Trust List + * (CTL). + * + * @see + * MSDN + */ + public static class CERT_EXTENSION extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "pszObjId", "fCritical", "Value"); + + public static class ByReference extends CERT_EXTENSION implements Structure.ByReference { + } + + public String pszObjId; + public boolean fCritical; + public DATA_BLOB Value; + + public CERT_EXTENSION() { + super(W32APITypeMapper.ASCII); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_EXTENSIONS structure contains an array of extensions. + * + * @see + * MSDN + */ + public static class CERT_EXTENSIONS extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cExtension", "rgExtension"); + + public static class ByReference extends CERT_EXTENSIONS implements Structure.ByReference { + } + + public int cExtension; + public Pointer rgExtension; + + public CERT_EXTENSION[] getRgExtension() { + CERT_EXTENSION[] elements = new CERT_EXTENSION[cExtension]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CERT_EXTENSION.class, + rgExtension.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_INFO structure contains the information of a certificate. + * + * @see + * MSDN + */ + public static class CERT_INFO extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwVersion", "SerialNumber", "SignatureAlgorithm", "Issuer", + "NotBefore", "NotAfter", "Subject", "SubjectPublicKeyInfo", + "IssuerUniqueId", "SubjectUniqueId", "cExtension", "rgExtension"); + + public static class ByReference extends CERT_INFO implements Structure.ByReference { + } + + public int dwVersion; + public DATA_BLOB SerialNumber; + public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; + public DATA_BLOB Issuer; + public FILETIME NotBefore; + public FILETIME NotAfter; + public DATA_BLOB Subject; + public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo; + public CRYPT_BIT_BLOB IssuerUniqueId; + public CRYPT_BIT_BLOB SubjectUniqueId; + public int cExtension; + public Pointer rgExtension; + + public CERT_EXTENSION[] getRgExtension() { + CERT_EXTENSION[] elements = new CERT_EXTENSION[cExtension]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CERT_EXTENSION.class, + rgExtension.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CERT_PUBLIC_KEY_INFO structure contains a public key and its + * algorithm. + * + * @see + * MSDN + */ + public static class CERT_PUBLIC_KEY_INFO extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "Algorithm", "PublicKey"); + + public static class ByReference extends CERT_PUBLIC_KEY_INFO implements Structure.ByReference { + } + + public CRYPT_ALGORITHM_IDENTIFIER Algorithm; + public CRYPT_BIT_BLOB PublicKey; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CRL_CONTEXT structure contains both the encoded and decoded + * representations of a certificate revocation list (CRL). CRL contexts + * returned by any CryptoAPI function must be freed by calling the + * CertFreeCRLContext function. + * + * @see + * MSDN + */ + public static class CRL_CONTEXT extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwCertEncodingType", "pbCrlEncoded", "cbCrlEncoded", + "pCrlInfo", "hCertStore"); + + public static class ByReference extends CRL_CONTEXT implements Structure.ByReference { + } + + public int dwCertEncodingType; + public Pointer pbCrlEncoded; + public int cbCrlEncoded; + public CRL_INFO.ByReference pCrlInfo; + public HCERTSTORE hCertStore; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CRL_ENTRY structure contains information about a single revoked + * certificate. It is a member of a CRL_INFO structure. + * + * @see + * MSDN + */ + public static class CRL_ENTRY extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "SerialNumber", "RevocationDate", "cExtension", "rgExtension"); + + public static class ByReference extends CRL_ENTRY implements Structure.ByReference { + } + + public DATA_BLOB SerialNumber; + public FILETIME RevocationDate; + public int cExtension; + public Pointer rgExtension; + + public CERT_EXTENSION[] getRgExtension() { + CERT_EXTENSION[] elements = new CERT_EXTENSION[cExtension]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CERT_EXTENSION.class, + rgExtension.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CRL_INFO structure contains the information of a certificate + * revocation list (CRL). + * + * @see + * MSDN + */ + public static class CRL_INFO extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwVersion", "SignatureAlgorithm", "Issuer", "ThisUpdate", + "NextUpdate", "cCRLEntry", "rgCRLEntry", "cExtension", + "rgExtension"); + + public static class ByReference extends CRL_INFO implements Structure.ByReference { + } + + public int dwVersion; + public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; + public DATA_BLOB Issuer; + public FILETIME ThisUpdate; + public FILETIME NextUpdate; + public int cCRLEntry; + public Pointer rgCRLEntry; + public int cExtension; + public Pointer rgExtension; + + public CRL_ENTRY[] getRgCRLEntry() { + CRL_ENTRY[] elements = new CRL_ENTRY[cCRLEntry]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CRL_ENTRY.class, + rgCRLEntry.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + public CERT_EXTENSION[] getRgExtension() { + CERT_EXTENSION[] elements = new CERT_EXTENSION[cExtension]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CERT_EXTENSION.class, + rgExtension.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CRYPT_ALGORITHM_IDENTIFIER structure specifies an algorithm used to + * encrypt a private key. The structure includes the object identifier (OID) + * of the algorithm and any needed parameters for that algorithm. The + * parameters contained in its CRYPT_OBJID_BLOB are encoded. + * + * @see + * MSDN + */ + public static class CRYPT_ALGORITHM_IDENTIFIER extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "pszObjId", "Parameters"); + + public static class ByReference extends CRYPT_ALGORITHM_IDENTIFIER implements Structure.ByReference { + } + + public String pszObjId; + public DATA_BLOB Parameters; + + public CRYPT_ALGORITHM_IDENTIFIER() { + super(W32APITypeMapper.ASCII); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CRYPT_ATTRIBUTE structure specifies an attribute that has one or more + * values. + * + * @see + * MSDN + */ + public static class CRYPT_ATTRIBUTE extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "pszObjId", "cValue", "rgValue"); + + public static class ByReference extends CRYPT_ATTRIBUTE implements Structure.ByReference { + } + + public String pszObjId; + public int cValue; + public DATA_BLOB.ByReference rgValue; + + public DATA_BLOB[] getRgValue() { + return (DATA_BLOB[]) rgValue.toArray(cValue); + } + + public CRYPT_ATTRIBUTE() { + super(W32APITypeMapper.ASCII); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CRYPT_BIT_BLOB structure contains a set of bits represented by an + * array of bytes. + * + * @see + * MSDN + */ + public static class CRYPT_BIT_BLOB extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbData", "pbData", "cUnusedBits"); + + public static class ByReference extends CRYPT_BIT_BLOB implements Structure.ByReference { + } + + public int cbData; + public Pointer pbData; + public int cUnusedBits; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CRYPT_KEY_PROV_INFO structure contains information about a key + * container within a cryptographic service provider (CSP). + * + * @see + * MSDN + */ + public static class CRYPT_KEY_PROV_INFO extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "pwszContainerName", "pwszProvName", "dwProvType", "dwFlags", + "cProvParam", "rgProvParam", "dwKeySpec"); + + public static class ByReference extends CRYPT_KEY_PROV_INFO implements Structure.ByReference { + } + + public String pwszContainerName; + public String pwszProvName; + public int dwProvType; + public int dwFlags; + public int cProvParam; + public Pointer rgProvParam; + public int dwKeySpec; + + public CRYPT_KEY_PROV_INFO() { + super(W32APITypeMapper.UNICODE); + } + + public CRYPT_KEY_PROV_PARAM[] getRgProvParam() { + CRYPT_KEY_PROV_PARAM[] elements = new CRYPT_KEY_PROV_PARAM[cProvParam]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CRYPT_KEY_PROV_PARAM.class, + rgProvParam.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CRYPT_KEY_PROV_PARAM structure contains information about a key + * container parameter. This structure is used with the CRYPT_KEY_PROV_INFO + * structure. + * + * @see + * MSDN + */ + public static class CRYPT_KEY_PROV_PARAM extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "dwParam", "pbData", "cbData", "dwFlags"); + + public static class ByReference extends CRYPT_KEY_PROV_PARAM implements Structure.ByReference { + } + + public int dwParam; + public Pointer pbData; + public int cbData; + public int dwFlags; + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CRYPT_SIGN_MESSAGE_PARA structure contains information for signing + * messages using a specified signing certificate context. + * + * @see + * MSDN + */ + public static class CRYPT_SIGN_MESSAGE_PARA extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "dwMsgEncodingType", "pSigningCert", "HashAlgorithm", + "pvHashAuxInfo", "cMsgCert", "rgpMsgCert", "cMsgCrl", + "rgpMsgCrl", "cAuthAttr", "rgAuthAttr", "cUnauthAttr", + "rgUnauthAttr", "dwFlags", "dwInnerContentType", + "HashEncryptionAlgorithm", "pvHashEncryptionAuxInfo"); + + public static class ByReference extends CRYPT_SIGN_MESSAGE_PARA implements Structure.ByReference { + } + + public int cbSize; + public int dwMsgEncodingType; + public CERT_CONTEXT.ByReference pSigningCert; + public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; + public Pointer pvHashAuxInfo; + public int cMsgCert; + public Pointer rgpMsgCert = null; + public int cMsgCrl; + public Pointer rgpMsgCrl = null; + public int cAuthAttr; + public Pointer rgAuthAttr = null; + public int cUnauthAttr; + public Pointer rgUnauthAttr = null; + public int dwFlags; + public int dwInnerContentType; + public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm; + public Pointer pvHashEncryptionAuxInfo; + + public CERT_CONTEXT[] getRgpMsgCert() { + CERT_CONTEXT[] elements = new CERT_CONTEXT[cMsgCrl]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CERT_CONTEXT.class, + rgpMsgCert.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + public CRL_CONTEXT[] getRgpMsgCrl() { + CRL_CONTEXT[] elements = new CRL_CONTEXT[cMsgCrl]; + for (int i = 0; i < elements.length; i++) { + elements[i] = Structure.newInstance( + CRL_CONTEXT.class, + rgpMsgCrl.getPointer(i * Native.POINTER_SIZE)); + elements[i].read(); + } + return elements; + } + + public CRYPT_ATTRIBUTE[] getRgAuthAttr() { + if (cAuthAttr == 0) { + return new CRYPT_ATTRIBUTE[0]; + } else { + return (CRYPT_ATTRIBUTE[]) Structure.newInstance( + CRYPT_ATTRIBUTE.class, + rgAuthAttr) + .toArray(cAuthAttr); + } + } + + public CRYPT_ATTRIBUTE[] getRgUnauthAttr() { + if (cUnauthAttr == 0) { + return new CRYPT_ATTRIBUTE[0]; + } else { + return (CRYPT_ATTRIBUTE[]) Structure.newInstance( + CRYPT_ATTRIBUTE.class, + rgUnauthAttr) + .toArray(cUnauthAttr); + } + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * The CryptGetSignerCertificateCallback user supplied callback function is + * used with the CRYPT_VERIFY_MESSAGE_PARA structure to get and verify a + * message signer's certificate. + */ + public interface CryptGetSignerCertificateCallback extends StdCallLibrary.StdCallCallback { + /** + * + * @param pvGetArg + * A pointer to user-defined data passed on to the + * verification function as specified in the CRYPT_VERIFY_MESSAGE_PARA + * structure. + * @param dwCertEncodingType + * Specifies the type of encoding used. It is always acceptable to + * specify both the certificate and message encoding types by combining + * them with a bitwise-OR operation as shown in the following example: + * + *

X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

+ * + *

Currently defined encoding types are:

+ * + *
    + *
  • X509_ASN_ENCODING
  • + *
  • PKCS_7_ASN_ENCODING
  • + *
+ * @param pSignerId A pointer to a CERT_INFO structure containing the + * issuer and serial number. Can be NULL if there is no content or + * signer. + * @param hMsgCertStore A handle to the certificate store containing all + * the certificates and CRLs in the signed message. + * @return + */ + public CERT_CONTEXT.ByReference callback(Pointer pvGetArg, int dwCertEncodingType, + CERT_INFO pSignerId, + HCERTSTORE hMsgCertStore); + } + + /** + * The CRYPT_VERIFY_MESSAGE_PARA structure contains information needed to + * verify signed messages. + * + * @see + * MSDN + */ + public static class CRYPT_VERIFY_MESSAGE_PARA extends Structure { + + private static final List fieldOrder = createFieldsOrder( + "cbSize", "dwMsgAndCertEncodingType", "hCryptProv", + "pfnGetSignerCertificate", "pvGetArg", "pStrongSignPara"); + + public static class ByReference extends CRYPT_SIGN_MESSAGE_PARA implements Structure.ByReference { + } + + public int cbSize; + public int dwMsgAndCertEncodingType; + public HCRYPTPROV_LEGACY hCryptProv; + public CryptGetSignerCertificateCallback pfnGetSignerCertificate; + public Pointer pvGetArg; + public CERT_STRONG_SIGN_PARA.ByReference pStrongSignPara; + + @Override + public void write() { + cbSize = size(); + super.write(); + } + + @Override + protected List getFieldOrder() { + return fieldOrder; + } + } + + /** + * Handle to a certificate chain engine. + */ + public static class HCERTCHAINENGINE extends HANDLE { + + /** + * Instantiates a new hcertchainengine. + */ + public HCERTCHAINENGINE() { + + } + + /** + * Instantiates a new hcertchainengine. + * + * @param p the p + */ + public HCERTCHAINENGINE(Pointer p) { + super(p); + } + } + + /** + * Handle to a certificate store. + */ + public static class HCERTSTORE extends HANDLE { + + /** + * Instantiates a new hcertstore. + */ + public HCERTSTORE() { + + } + + /** + * Instantiates a new hcertstore. + * + * @param p + * the p + */ + public HCERTSTORE(Pointer p) { + super(p); + } + } + + /** + * Handle to a cryptographic message. + */ + public static class HCRYPTMSG extends HANDLE { + /** + * Instantiates a new hcryptmgr. + */ + public HCRYPTMSG() { + + } + + /** + * Instantiates a new hcryptmsg. + * + * @param p + * the p + */ + public HCRYPTMSG(Pointer p) { + super(p); + } + } + + public static class HCRYPTPROV_LEGACY extends BaseTSD.ULONG_PTR { + + public HCRYPTPROV_LEGACY() { + } + + public HCRYPTPROV_LEGACY(long value) { + super(value); + } + } + /** * The CRYPTPROTECT_PROMPTSTRUCT structure provides the text of a prompt and * information about when and where that prompt is to be displayed when using @@ -301,4 +1617,267 @@ protected List getFieldOrder() { * @see MSDN */ int CRYPT_E_ASN1_NOEOD = 0x80093202; + + /** + * Message Encoding Type. + * + * @see MSDN + */ + int CRYPT_ASN_ENCODING = 0x00000001; + + /** + * Message Encoding Type. + * + * @see MSDN + */ + int CRYPT_NDR_ENCODING = 0x00000002; + + /** + * Message Encoding Type. + * + * @see MSDN + */ + int X509_ASN_ENCODING = 0x00000001; + + /** + * Message Encoding Type. + * + * @see MSDN + */ + int X509_NDR_ENCODING = 0x00000002; + + /** + * Message Encoding Type. + * + * @see MSDN + */ + int PKCS_7_ASN_ENCODING = 0x00010000; + + /** + * Message Encoding Type. + * + * @see MSDN + */ + int PKCS_7_NDR_ENCODING = 0x00020000; + + /** + * Determines the kind of issuer matching to be done. + * + * @see MSDN + */ + int USAGE_MATCH_TYPE_AND = 0x00000000; + + /** + * Determines the kind of issuer matching to be done. + * + * @see MSDN + */ + int USAGE_MATCH_TYPE_OR = 0x00000001; + + /** + * Set the window handle that the provider uses as the parent of any dialog + * boxes it creates. + * + * @see MSDN + */ + int PP_CLIENT_HWND = 1; + + /** + * Certificate name string type. + * + * @see MSDN + */ + int CERT_SIMPLE_NAME_STR = 1; + + /** + * Certificate name string type. + * + * @see MSDN + */ + int CERT_OID_NAME_STR = 2; + + /** + * Certificate name string type. + * + * @see MSDN + */ + int CERT_X500_NAME_STR = 3; + + /** + * Certificate name string type. + * + * @see MSDN + */ + int CERT_XML_NAME_STR = 4; + + /** + * Predefined verify chain policies. + * + * @see MSDN + */ + int CERT_CHAIN_POLICY_BASE = 1; + + /** + * Algorithm object identifiers RSA. + * + * @see MSDN + */ + String szOID_RSA_SHA1RSA = "1.2.840.113549.1.1.5"; + + /** + * Predefined certificate chain engine values. + * + * @see + * MSDN + */ + HCERTCHAINENGINE HCCE_CURRENT_USER = new HCERTCHAINENGINE(Pointer.createConstant(0x0)); + + /** + * Predefined certificate chain engine values. + * + * @see + * MSDN + */ + HCERTCHAINENGINE HCCE_LOCAL_MACHINE = new HCERTCHAINENGINE(Pointer.createConstant(0x1)); + + /** + * Predefined certificate chain engine values. + * + * @see + * MSDN + */ + HCERTCHAINENGINE HCCE_SERIAL_LOCAL_MACHINE = new HCERTCHAINENGINE(Pointer.createConstant(0x2)); + + /** + * Certificate comparison functions. + * + * @see MSDN + */ + int CERT_COMPARE_SHIFT = 16; + + /** + * Certificate comparison functions. + * + * @see MSDN + */ + int CERT_COMPARE_NAME_STR_W = 8; + + /** + * Certificate comparison functions. + * + * @see MSDN + */ + int CERT_INFO_SUBJECT_FLAG = 7; + + /** + * Certificate comparison functions. + * + * @see MSDN + */ + int CERT_FIND_SUBJECT_STR_W = (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG); + + /** + * Certificate comparison functions. + * + * @see MSDN + */ + int CERT_FIND_SUBJECT_STR = CERT_FIND_SUBJECT_STR_W; + + /** + * Imported keys are marked as exportable. If this flag is not used, calls + * to the CryptExportKey function with the key handle fail. + */ + int CRYPT_EXPORTABLE = 0x00000001; + + /** + * The user is to be notified through a dialog box or other method when + * certain attempts to use this key are made. The precise behavior is + * specified by the cryptographic service provider (CSP) being used. + * + *

+ * Prior to Internet Explorer 4.0, Microsoft cryptographic service providers + * ignored this flag. Starting with Internet Explorer 4.0, Microsoft + * providers support this flag.

+ * + *

+ * If the provider context was opened with the CRYPT_SILENT flag set, using + * this flag causes a failure and the last error is set to + * NTE_SILENT_CONTEXT.

+ */ + int CRYPT_USER_PROTECTED = 0x00000002; + + /** + * The private keys are stored under the local computer and not under the + * current user. + */ + int CRYPT_MACHINE_KEYSET = 0x00000020; + + /** + * The private keys are stored under the current user and not under the + * local computer even if the PFX BLOB specifies that they should go into + * the local computer. + */ + int CRYPT_USER_KEYSET = 0x00001000; + + /** + * Indicates that the CNG key storage provider (KSP) is preferred. If the + * CSP is specified in the PFX file, then the CSP is used, otherwise the KSP + * is preferred. If the CNG KSP is unavailable, the PFXImportCertStore + * function will fail. + */ + int PKCS12_PREFER_CNG_KSP = 0x00000100; + + /** + * Indicates that the CNG KSP is always used. When specified, + * PFXImportCertStore attempts to use the CNG KSP irrespective of provider + * information in the PFX file. If the CNG KSP is unavailable, the import + * will not fail. + */ + int PKCS12_ALWAYS_CNG_KSP = 0x00000200; + + /** + * Allow overwrite of the existing key. Specify this flag when you encounter + * a scenario in which you must import a PFX file that contains a key name + * that already exists. For example, when you import a PFX file, it is + * possible that a container of the same name is already present because + * there is no unique namespace for key containers. If you have created a + * "TestKey" on your computer, and then you import a PFX file that also has + * "TestKey" as the key container, the PKCS12_ALLOW_OVERWRITE_KEY setting + * allows the key to be overwritten. + */ + int PKCS12_ALLOW_OVERWRITE_KEY = 0x00004000; + + /** + * Do not persist the key. Specify this flag when you do not want to persist + * the key. For example, if it is not necessary to store the key after + * verification, then instead of creating a container and then deleting it, + * you can specify this flag to dispose of the key immediately. + */ + int PKCS12_NO_PERSIST_KEY = 0x00008000; + + /** + * Import all extended properties on the certificate that were saved on the + * certificate when it was exported. + */ + int PKCS12_INCLUDE_EXTENDED_PROPERTIES = 0x0010; + + /** + * Checks for nonfreed certificate, CRL, and CTL contexts. A returned error + * code indicates that one or more store elements is still in use. This flag + * should only be used as a diagnostic tool in the development of + * applications. + */ + int CERT_CLOSE_STORE_FORCE_FLAG = 0x00000001; + /** + * Forces the freeing of memory for all contexts associated with the store. + * This flag can be safely used only when the store is opened in a function + * and neither the store handle nor any of its contexts are passed to any + * called functions. For details, see Remarks. + */ + int CERT_CLOSE_STORE_CHECK_FLAG = 0x00000002; } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinCryptUtil.java b/contrib/platform/src/com/sun/jna/platform/win32/WinCryptUtil.java new file mode 100644 index 0000000000..fb5d8c6eff --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinCryptUtil.java @@ -0,0 +1,176 @@ +/* Copyright (c) 2018 Matthias Bläsing, All Rights Reserved + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.win32; + +import com.sun.jna.Memory; +import com.sun.jna.Native; +import com.sun.jna.platform.win32.WinCrypt.CERT_CONTEXT; +import com.sun.jna.platform.win32.WinCrypt.CRL_CONTEXT; +import com.sun.jna.platform.win32.WinCrypt.CRYPT_ATTRIBUTE; +import com.sun.jna.platform.win32.WinCrypt.CRYPT_SIGN_MESSAGE_PARA; + + +public abstract class WinCryptUtil { + + public static class MANAGED_CRYPT_SIGN_MESSAGE_PARA extends CRYPT_SIGN_MESSAGE_PARA { + + private CERT_CONTEXT[] rgpMsgCerts; + private CRL_CONTEXT[] rgpMsgCrls; + private CRYPT_ATTRIBUTE[] rgAuthAttrs; + private CRYPT_ATTRIBUTE[] rgUnauthAttrs; + + public void setRgpMsgCert(CERT_CONTEXT[] rgpMsgCerts) { + this.rgpMsgCerts = rgpMsgCerts; + if (rgpMsgCerts == null || rgpMsgCerts.length == 0) { + rgpMsgCert = null; + cMsgCert = 0; + } else { + cMsgCert = rgpMsgCerts.length; + Memory mem = new Memory(Native.POINTER_SIZE * rgpMsgCerts.length); + for (int i = 0; i < rgpMsgCerts.length; i++) { + mem.setPointer(i * Native.POINTER_SIZE, rgpMsgCerts[i].getPointer()); + } + rgpMsgCert = mem; + } + } + + @Override + public CERT_CONTEXT[] getRgpMsgCert() { + return rgpMsgCerts; + } + + public void setRgpMsgCrl(CRL_CONTEXT[] rgpMsgCrls) { + this.rgpMsgCrls = rgpMsgCrls; + if (rgpMsgCrls == null || rgpMsgCrls.length == 0) { + rgpMsgCert = null; + cMsgCert = 0; + } else { + cMsgCert = rgpMsgCrls.length; + Memory mem = new Memory(Native.POINTER_SIZE * rgpMsgCrls.length); + for (int i = 0; i < rgpMsgCrls.length; i++) { + mem.setPointer(i * Native.POINTER_SIZE, rgpMsgCrls[i].getPointer()); + } + rgpMsgCert = mem; + } + } + + @Override + public CRL_CONTEXT[] getRgpMsgCrl() { + return rgpMsgCrls; + } + + /** + * @param rgAuthAttrs array of CRYPT_ATTRIBUTE - it must be created from + * a continous memory region (manually allocated memory or + * CRYPT_ATTRIBUTE#toArray) + */ + public void setRgAuthAttr(CRYPT_ATTRIBUTE[] rgAuthAttrs) { + this.rgAuthAttrs = rgAuthAttrs; + if (rgAuthAttrs == null || rgAuthAttrs.length == 0) { + rgAuthAttr = null; + cMsgCert = 0; + } else { + cMsgCert = rgpMsgCerts.length; + rgAuthAttr = rgAuthAttrs[0].getPointer(); + } + } + + @Override + public CRYPT_ATTRIBUTE[] getRgAuthAttr() { + return rgAuthAttrs; + } + + /** + * @param rgUnauthAttrs array of CRYPT_ATTRIBUTE - it must be created + * from a continous memory region (manually allocated memory or + * CRYPT_ATTRIBUTE#toArray) + */ + public void setRgUnauthAttr(CRYPT_ATTRIBUTE[] rgUnauthAttrs) { + this.rgUnauthAttrs = rgUnauthAttrs; + if (rgUnauthAttrs == null || rgUnauthAttrs.length == 0) { + rgUnauthAttr = null; + cMsgCert = 0; + } else { + cMsgCert = rgpMsgCerts.length; + rgUnauthAttr = rgUnauthAttrs[0].getPointer(); + } + } + + @Override + public CRYPT_ATTRIBUTE[] getRgUnauthAttr() { + return rgUnauthAttrs; + } + + @Override + public void write() { + if (rgpMsgCerts != null) { + for (CERT_CONTEXT cc : rgpMsgCerts) { + cc.write(); + } + } + if (rgpMsgCrls != null) { + for (CRL_CONTEXT cc : rgpMsgCrls) { + cc.write(); + } + } + if (rgAuthAttrs != null) { + for (CRYPT_ATTRIBUTE cc : rgAuthAttrs) { + cc.write(); + } + } + if (rgUnauthAttrs != null) { + for (CRYPT_ATTRIBUTE cc : rgUnauthAttrs) { + cc.write(); + } + } + cbSize = size(); + super.write(); + } + + @Override + public void read() { + if (rgpMsgCerts != null) { + for (CERT_CONTEXT cc : rgpMsgCerts) { + cc.read(); + } + } + if (rgpMsgCrls != null) { + for (CRL_CONTEXT cc : rgpMsgCrls) { + cc.read(); + } + } + if (rgAuthAttrs != null) { + for (CRYPT_ATTRIBUTE cc : rgAuthAttrs) { + cc.read(); + } + } + if (rgUnauthAttrs != null) { + for (CRYPT_ATTRIBUTE cc : rgUnauthAttrs) { + cc.read(); + } + } + super.read(); + } + } +} diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Crypt32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Crypt32Test.java index 246aca0977..0083ebab83 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Crypt32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Crypt32Test.java @@ -11,10 +11,26 @@ * Lesser General Public License for more details. */ package com.sun.jna.platform.win32; +import java.security.*; +import java.security.cert.X509Certificate; +import sun.security.tools.keytool.*; +import sun.security.x509.X500Name; import com.sun.jna.Native; import com.sun.jna.platform.win32.WinCrypt.DATA_BLOB; import com.sun.jna.ptr.PointerByReference; +import com.sun.jna.platform.win32.WinCrypt.*; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.Memory; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import com.sun.jna.platform.win32.WTypes.LPSTR; +import com.sun.jna.platform.win32.WinCryptUtil.MANAGED_CRYPT_SIGN_MESSAGE_PARA; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; import junit.framework.TestCase; @@ -22,10 +38,40 @@ * @author dblock[at]dblock[dot]org */ public class Crypt32Test extends TestCase { + private static final String TESTCERT_CN = "cryptsigntest"; + + /** + * Track if the test certificate was created during the test. + */ + private boolean createdCertificate = false; public static void main(String[] args) { junit.textui.TestRunner.run(Crypt32Test.class); } + + @Override + protected void setUp() { + HCERTSTORE hCertStore = Crypt32.INSTANCE.CertOpenSystemStore(Pointer.NULL, "MY"); + + CERT_CONTEXT.ByReference pc = Crypt32.INSTANCE.CertFindCertificateInStore( + hCertStore, + (WinCrypt.PKCS_7_ASN_ENCODING | WinCrypt.X509_ASN_ENCODING), + 0, + WinCrypt.CERT_FIND_SUBJECT_STR, + new WTypes.LPWSTR(TESTCERT_CN).getPointer(), + null); + + if (pc == null) { + createdCertificate = createTestCertificate(); + } + } + + @Override + protected void tearDown() { + if(createdCertificate) { + removeTestCertificate(); + } + } public void testCryptProtectUnprotectData() { DATA_BLOB pDataIn = new DATA_BLOB("hello world"); @@ -87,10 +133,297 @@ public void testCryptProtectUnprotectDataWithEntropy() { } } - public void testCertAddEncodedCertificateToSystemStore() { - // try to install a non-existent certificate - assertFalse("Attempting to install a non-existent certificate should have returned false and set GetLastError()", Crypt32.INSTANCE.CertAddEncodedCertificateToSystemStore("ROOT", null, 0)); - // should fail with "unexpected end of data" - assertEquals("GetLastError() should have been set to CRYPT_E_ASN1_EOD ('ASN.1 unexpected end of data' in WinCrypt.h)", WinCrypt.CRYPT_E_ASN1_EOD, Native.getLastError()); - } + public void testCertAddEncodedCertificateToSystemStore() { + // try to install a non-existent certificate + assertFalse("Attempting to install a non-existent certificate should have returned false and set GetLastError()", Crypt32.INSTANCE.CertAddEncodedCertificateToSystemStore("ROOT", null, 0)); + // should fail with "unexpected end of data" + assertEquals("GetLastError() should have been set to CRYPT_E_ASN1_EOD ('ASN.1 unexpected end of data' in WinCrypt.h)", WinCrypt.CRYPT_E_ASN1_EOD, Native.getLastError()); + } + + public void testCryptSignMessage() { + // Open user keystore + HCERTSTORE hCertStore = Crypt32.INSTANCE.CertOpenSystemStore(Pointer.NULL, "MY"); + + assertNotNull(hCertStore); + + // Acquire test certificate (created in setup routine) + CERT_CONTEXT.ByReference signCertContext = Crypt32.INSTANCE.CertFindCertificateInStore( + hCertStore, + (WinCrypt.PKCS_7_ASN_ENCODING | WinCrypt.X509_ASN_ENCODING), + 0, + WinCrypt.CERT_FIND_SUBJECT_STR, + new WTypes.LPWSTR(TESTCERT_CN).getPointer(), + null); + + assertNotNull(signCertContext); + + if (signCertContext.pCertInfo.cExtension > 0) { + assertTrue(signCertContext.pCertInfo.cExtension == signCertContext.pCertInfo.getRgExtension().length); + } + + // Create sample message + String message1String = "Message Part 1 öäü"; + Memory message1 = new Memory((message1String.length() + 1) * Native.WCHAR_SIZE); + message1.setWideString(0, message1String); + + // Prepare signing + MANAGED_CRYPT_SIGN_MESSAGE_PARA sigParams = new MANAGED_CRYPT_SIGN_MESSAGE_PARA(); + sigParams.dwMsgEncodingType = WinCrypt.X509_ASN_ENCODING | WinCrypt.PKCS_7_ASN_ENCODING; + sigParams.pSigningCert = signCertContext; + sigParams.HashAlgorithm.pszObjId = WinCrypt.szOID_RSA_SHA1RSA; + sigParams.HashAlgorithm.Parameters.cbData = 0; + sigParams.setRgpMsgCert(new CERT_CONTEXT[]{signCertContext}); + + Pointer[] rgpbToBeSigned = {message1}; + int[] rgcbToBeSigned = {(int) message1.size()}; + + IntByReference pcbSignedBlob1 = new IntByReference(0); + + // First determine required size of the required buffer + boolean result = Crypt32.INSTANCE.CryptSignMessage( + sigParams, + false, + rgpbToBeSigned.length, + rgpbToBeSigned, + rgcbToBeSigned, + Pointer.NULL, + pcbSignedBlob1); + + assertTrue("Failed to determine buffer size required for signing", result); + + Memory resultBuffer = new Memory(pcbSignedBlob1.getValue()); + + // Create signed/encrypted buffer + result = Crypt32.INSTANCE.CryptSignMessage( + sigParams, + false, + rgpbToBeSigned.length, + rgpbToBeSigned, + rgcbToBeSigned, + resultBuffer, + pcbSignedBlob1); + + assertTrue("Failed to sign buffer", result); + + // Prepare verification + CRYPT_VERIFY_MESSAGE_PARA verifyMessagePara = new CRYPT_VERIFY_MESSAGE_PARA(); + verifyMessagePara.dwMsgAndCertEncodingType = WinCrypt.X509_ASN_ENCODING | WinCrypt.PKCS_7_ASN_ENCODING; + verifyMessagePara.hCryptProv = null; + verifyMessagePara.pfnGetSignerCertificate = null; + verifyMessagePara.pvGetArg = null; + + IntByReference decodedBlobSize = new IntByReference(); + + // Determine required buffer size for decoded buffer + result = Crypt32.INSTANCE.CryptVerifyMessageSignature( + verifyMessagePara, 0, resultBuffer, + (int) resultBuffer.size(), null, + decodedBlobSize, null); + + assertTrue("Failed to determine buffer size required for verification", result); + + Memory resultBuffer2 = new Memory(decodedBlobSize.getValue()); + + PointerByReference certContextPointer = new PointerByReference(); + + result = Crypt32.INSTANCE.CryptVerifyMessageSignature( + verifyMessagePara, 0, resultBuffer, + (int) resultBuffer.size(), resultBuffer2, + decodedBlobSize, certContextPointer); + + assertTrue("Verification failed", result); + assertEquals(message1String, resultBuffer2.getWideString(0)); + + assertNotNull(certContextPointer.getValue()); + CERT_CONTEXT resCertContext = Structure.newInstance(CERT_CONTEXT.class, certContextPointer.getValue()); + + Crypt32.INSTANCE.CertFreeCertificateContext(signCertContext); + Crypt32.INSTANCE.CertFreeCertificateContext(resCertContext); + + assertTrue("CERT_CONTEXT or CERT_CHAIN_CONTEXT were not correctly freed.", + Crypt32.INSTANCE.CertCloseStore(hCertStore, WinCrypt.CERT_CLOSE_STORE_CHECK_FLAG)); + } + + public void testCertGetCertificateChain() throws IOException { + byte[] testP12 = getBytes("/res/test.p12"); + DATA_BLOB testP12Blob = new DATA_BLOB(testP12); + + HCERTSTORE hCertStore = Crypt32.INSTANCE.PFXImportCertStore(testP12Blob, new WTypes.LPWSTR("test"), 0); + + assertNotNull(hCertStore); + + CERT_CONTEXT.ByReference pc = Crypt32.INSTANCE.CertFindCertificateInStore(hCertStore, + (WinCrypt.PKCS_7_ASN_ENCODING | WinCrypt.X509_ASN_ENCODING), 0, WinCrypt.CERT_FIND_SUBJECT_STR, + new WTypes.LPWSTR("www.doppel-helix.eu").getPointer(), null); + + assertNotNull(pc); + + CERT_CHAIN_PARA pChainPara = new CERT_CHAIN_PARA(); + + pChainPara.cbSize = pChainPara.size(); + pChainPara.RequestedUsage.dwType = WinCrypt.USAGE_MATCH_TYPE_AND; + pChainPara.RequestedUsage.Usage.cUsageIdentifier = 0; + pChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = null; + + PointerByReference pbr = new PointerByReference(); + boolean status = Crypt32.INSTANCE.CertGetCertificateChain(null, pc, null, null, pChainPara, 0, null, + pbr); + + assertTrue("Assert that the operation succeeded when done with a valid certificate.", status); + assertNotNull("Assert that a returned certificate chain context was returned.", pbr.getValue()); + CERT_CHAIN_CONTEXT pChainContext = Structure.newInstance(CERT_CHAIN_CONTEXT.class, pbr.getValue()); + pChainContext.read(); + + Pointer[] chainPointers = new Pointer[pChainContext.cChain]; + pChainContext.rgpChain.read(0, chainPointers, 0, chainPointers.length); + + CERT_SIMPLE_CHAIN csc = Structure.newInstance(CERT_SIMPLE_CHAIN.class, chainPointers[0]); + csc.read(); + CERT_CHAIN_ELEMENT[] element = csc.getRgpElement(); + assertEquals("Certificate chain does not contain 3 elements", 3, element.length); + for (int i = 0; i < element.length; i++) { + String subjectName = Crypt32Util.CertNameToStr( + WinCrypt.X509_ASN_ENCODING, + WinCrypt.CERT_SIMPLE_NAME_STR, + element[i].pCertContext.pCertInfo.Subject); + switch(i) { + case 0: + assertEquals("www.doppel-helix.eu", subjectName); + break; + case 1: + assertEquals("US, Let's Encrypt, Let's Encrypt Authority X3", subjectName); + break; + case 2: + assertEquals("Digital Signature Trust Co., DST Root CA X3", subjectName); + break; + } + } + + // Extract usage identifiers for root certificate + String[] usagesArray = element[2].pApplicationUsage.getRgpszUsageIdentier(); + assertNotNull(usagesArray); + assertEquals(6, usagesArray.length); + List usages = Arrays.asList(usagesArray); + assertTrue(usages.contains("1.3.6.1.5.5.7.3.1")); // Indicates that a certificate can be used as an SSL server certificate. + assertTrue(usages.contains("1.3.6.1.5.5.7.3.2")); // Indicates that a certificate can be used as an SSL client certificate. + assertTrue(usages.contains("1.3.6.1.5.5.7.3.4")); // Indicates that a certificate can be used for protecting email (signing, encryption, key agreement). + assertTrue(usages.contains("1.3.6.1.5.5.7.3.8")); // Indicates that a certificate can be used to bind the hash of an object to a time from a trusted time source. + assertTrue(usages.contains("1.3.6.1.4.1.311.10.3.4")); // Can use encrypted file systems (EFS) - szOID_EFS_CRYPTO + assertTrue(usages.contains("1.3.6.1.4.1.311.10.3.12")); // Signer of documents - szOID_KP_DOCUMENT_SIGNING + + Crypt32.INSTANCE.CertFreeCertificateChain(pChainContext); + Crypt32.INSTANCE.CertFreeCertificateContext(pc); + + assertTrue("CERT_CONTEXT or CERT_CHAIN_CONTEXT were not correctly freed.", + Crypt32.INSTANCE.CertCloseStore(hCertStore, WinCrypt.CERT_CLOSE_STORE_CHECK_FLAG)); + } + + public void testCertNameToStr() { + // Open user keystore + HCERTSTORE hCertStore = Crypt32.INSTANCE.CertOpenSystemStore(Pointer.NULL, "MY"); + + // Acquire test certificate (created in setup routine) + CERT_CONTEXT.ByReference pc = Crypt32.INSTANCE.CertFindCertificateInStore( + hCertStore, + (WinCrypt.PKCS_7_ASN_ENCODING | WinCrypt.X509_ASN_ENCODING), + 0, + WinCrypt.CERT_FIND_SUBJECT_STR, + new WTypes.LPWSTR(TESTCERT_CN).getPointer(), + null); + + assertNotNull(pc); + + // Initialize the signature structure. + int requiredSize = Crypt32.INSTANCE.CertNameToStr( + WinCrypt.X509_ASN_ENCODING, + pc.pCertInfo.Issuer, + WinCrypt.CERT_SIMPLE_NAME_STR, + Pointer.NULL, + 0); + + assertEquals("Issuer Name length repored incorrectly", TESTCERT_CN.length() + 1, requiredSize); + + Memory mem = new Memory(requiredSize * Native.WCHAR_SIZE); + + int resultSize = Crypt32.INSTANCE.CertNameToStr( + WinCrypt.X509_ASN_ENCODING, + pc.pCertInfo.Issuer, + WinCrypt.CERT_SIMPLE_NAME_STR, + mem, + requiredSize); + + assertEquals(TESTCERT_CN, mem.getWideString(0)); + + String utilResult = Crypt32Util.CertNameToStr(WinCrypt.X509_ASN_ENCODING, WinCrypt.CERT_SIMPLE_NAME_STR, pc.pCertInfo.Issuer); + + assertEquals(TESTCERT_CN, utilResult); + } + + public void testCertVerifyCertificateChainPolicy() { + CERT_CHAIN_CONTEXT pChainContext = new CERT_CHAIN_CONTEXT(); + + CERT_CHAIN_POLICY_PARA ChainPolicyPara = new CERT_CHAIN_POLICY_PARA(); + CERT_CHAIN_POLICY_STATUS PolicyStatus = new CERT_CHAIN_POLICY_STATUS(); + + ChainPolicyPara.cbSize = ChainPolicyPara.size(); + ChainPolicyPara.dwFlags = 0; + + PolicyStatus.cbSize = PolicyStatus.size(); + boolean status = Crypt32.INSTANCE.CertVerifyCertificateChainPolicy( + new LPSTR(Pointer.createConstant(WinCrypt.CERT_CHAIN_POLICY_BASE)), pChainContext, ChainPolicyPara, + PolicyStatus); + assertTrue("The status would be true since a valid certificate chain was not passed in.", status); + } + + private boolean createTestCertificate() { + try { + KeyStore keyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI"); + keyStore.load(null, null); + + CertAndKeyGen certAndKeyGen = new CertAndKeyGen("RSA", "SHA256WithRSA", null); + certAndKeyGen.generate(1024); + + X509Certificate certificate = certAndKeyGen.getSelfCertificate(new X500Name("CN=cryptsigntest"), 24 * 60 * 60); + + keyStore.setKeyEntry(TESTCERT_CN, certAndKeyGen.getPrivateKey(), null, new X509Certificate[]{certificate}); + } catch (Exception e) { + System.out.println("Unable to complete test. Certificate creation failed."); + return false; + } + + return true; + } + + private boolean removeTestCertificate() { + try { + KeyStore keyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI"); + keyStore.load(null, null); + keyStore.deleteEntry(TESTCERT_CN); + } catch (Exception e) { + System.out.println("Test certificate deletion failed."); + return false; + } + + return true; + } + + private static byte[] getBytes(String path) throws IOException { + InputStream is = Crypt32Test.class.getResourceAsStream(path); + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int read; + byte[] buffer = new byte[10240]; + while ((read = is.read(buffer)) > 0) { + baos.write(buffer, 0, read); + } + return baos.toByteArray(); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException ex) { + } + } + } + } } \ No newline at end of file diff --git a/contrib/platform/test/com/sun/jna/platform/win32/CryptuiTest.java b/contrib/platform/test/com/sun/jna/platform/win32/CryptuiTest.java new file mode 100644 index 0000000000..bf82737026 --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/win32/CryptuiTest.java @@ -0,0 +1,47 @@ +/* Copyright (c) 2018 Roshan Muralidharan, All Rights Reserved + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.win32; + +import com.sun.jna.Native; +import com.sun.jna.platform.win32.WinCrypt.DATA_BLOB; +import com.sun.jna.ptr.PointerByReference; +import com.sun.jna.platform.win32.WinCrypt.*; + +import junit.framework.TestCase; + +/** + * @author roshan[dot]muralidharan[at]cerner[dot]com + */ +public class CryptuiTest extends TestCase { + + public static void main(String[] args) { + junit.textui.TestRunner.run(CryptuiTest.class); + } + + public void testCryptUIDlgSelectCertificateFromStore() { + CERT_CONTEXT.ByReference context = Cryptui.INSTANCE.CryptUIDlgSelectCertificateFromStore(null, null, "", "", 2, 0, null); + + assertNull("Context should be null as a valid certificate store handle was not provided.", context); + } +} \ No newline at end of file diff --git a/contrib/platform/test/com/sun/jna/platform/win32/WTypesTest.java b/contrib/platform/test/com/sun/jna/platform/win32/WTypesTest.java index 91dd0ba93f..561d087c9b 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/WTypesTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/WTypesTest.java @@ -22,10 +22,13 @@ public class WTypesTest extends TestCase { private static final String TEST_STRING = "input"; - private static final Pointer TEST_POINTER = new Memory((TEST_STRING.length() + 1L) * Native.WCHAR_SIZE); + private static final Pointer TEST_POINTER_WCHAR = new Memory((TEST_STRING.length() + 1L) * Native.WCHAR_SIZE); + + private static final Pointer TEST_POINTER_CHAR = new Memory(TEST_STRING.length() + 1L); static { - TEST_POINTER.setWideString(0, TEST_STRING); + TEST_POINTER_WCHAR.setWideString(0, TEST_STRING); + TEST_POINTER_CHAR.setString(0, TEST_STRING); } public void testLPOLESTRConstruction() { @@ -33,7 +36,7 @@ public void testLPOLESTRConstruction() { assertEquals(fromString.getValue(), TEST_STRING); WTypes.LPOLESTR empty = new WTypes.LPOLESTR(); assertNull(empty.getValue()); - WTypes.LPOLESTR fromPointer = new WTypes.LPOLESTR(TEST_POINTER); + WTypes.LPOLESTR fromPointer = new WTypes.LPOLESTR(TEST_POINTER_WCHAR); assertEquals(fromPointer.getValue(), TEST_STRING); } @@ -42,7 +45,7 @@ public void testLPSTRConstruction() { assertEquals(instance.getValue(), TEST_STRING); WTypes.LPSTR empty = new WTypes.LPSTR(); assertNull(empty.getValue()); - WTypes.LPSTR fromPointer = new WTypes.LPSTR(TEST_POINTER); + WTypes.LPSTR fromPointer = new WTypes.LPSTR(TEST_POINTER_CHAR); assertEquals(fromPointer.getValue(), TEST_STRING); } @@ -51,7 +54,7 @@ public void testLPWSTRConstruction() { assertEquals(instance.getValue(), TEST_STRING); WTypes.LPWSTR empty = new WTypes.LPWSTR(); assertNull(empty.getValue()); - WTypes.LPWSTR fromPointer = new WTypes.LPWSTR(TEST_POINTER); + WTypes.LPWSTR fromPointer = new WTypes.LPWSTR(TEST_POINTER_WCHAR); assertEquals(fromPointer.getValue(), TEST_STRING); } diff --git a/contrib/platform/test/res/test.p12 b/contrib/platform/test/res/test.p12 new file mode 100644 index 0000000000..fc720e690c Binary files /dev/null and b/contrib/platform/test/res/test.p12 differ diff --git a/www/Contributing.md b/www/Contributing.md index 9ddd727113..897a212cbe 100644 --- a/www/Contributing.md +++ b/www/Contributing.md @@ -6,7 +6,7 @@ JNA contains work from many developers. You're encouraged to contribute to both - Install Git and configure it to work with Github - Fork the code from [github.com/twall/jna](https://github.com/java-native-access/jna) - Check out the code with `git clone git@github.com:username/jna.git` -- Ensure you can build the project with `ant dist test` +- Ensure you can build the project with `ant dist test test-platform` - Make your code changes, write tests, build - Submit pull requests, forks and/or topical branches are encouraged. @@ -28,7 +28,7 @@ For debian-style installs, For most unix-like systems: % git clone git@github.com:java-native-access/jna - % ant dist test + % ant dist test test-platform For Windows, see [Windows Development Environment](WindowsDevelopmentEnvironment.md).