xref: /AOO41X/main/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx (revision d0626817eadca72252d341a27a0d42c4a6bf2287)
1*d0626817SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*d0626817SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*d0626817SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*d0626817SAndrew Rist  * distributed with this work for additional information
6*d0626817SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*d0626817SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*d0626817SAndrew Rist  * "License"); you may not use this file except in compliance
9*d0626817SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*d0626817SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*d0626817SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*d0626817SAndrew Rist  * software distributed under the License is distributed on an
15*d0626817SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*d0626817SAndrew Rist  * KIND, either express or implied.  See the License for the
17*d0626817SAndrew Rist  * specific language governing permissions and limitations
18*d0626817SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*d0626817SAndrew Rist  *************************************************************/
21*d0626817SAndrew Rist 
22*d0626817SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #include <precompiled_xmlsecurity.hxx>
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #include <osl/time.h>
27cdf0e10cSrcweir #include <rtl/random.h>
28cdf0e10cSrcweir #include <rtl/ref.hxx>
29cdf0e10cSrcweir 
30cdf0e10cSrcweir #include "ciphercontext.hxx"
31cdf0e10cSrcweir 
32cdf0e10cSrcweir using namespace ::com::sun::star;
33cdf0e10cSrcweir 
34cdf0e10cSrcweir uno::Reference< xml::crypto::XCipherContext > OCipherContext::Create( CK_MECHANISM_TYPE nNSSCipherID, const uno::Sequence< ::sal_Int8 >& aKey, const uno::Sequence< ::sal_Int8 >& aInitializationVector, bool bEncryption, bool bW3CPadding )
35cdf0e10cSrcweir {
36cdf0e10cSrcweir     ::rtl::Reference< OCipherContext > xResult = new OCipherContext;
37cdf0e10cSrcweir 
38cdf0e10cSrcweir     xResult->m_pSlot = PK11_GetBestSlot( nNSSCipherID, NULL );
39cdf0e10cSrcweir     if ( xResult->m_pSlot )
40cdf0e10cSrcweir     {
41cdf0e10cSrcweir         SECItem aKeyItem = { siBuffer, const_cast< unsigned char* >( reinterpret_cast< const unsigned char* >( aKey.getConstArray() ) ), aKey.getLength() };
42cdf0e10cSrcweir         xResult->m_pSymKey = PK11_ImportSymKey( xResult->m_pSlot, nNSSCipherID, PK11_OriginDerive, bEncryption ? CKA_ENCRYPT : CKA_DECRYPT, &aKeyItem, NULL );
43cdf0e10cSrcweir         if ( xResult->m_pSymKey )
44cdf0e10cSrcweir         {
45cdf0e10cSrcweir             SECItem aIVItem = { siBuffer, const_cast< unsigned char* >( reinterpret_cast< const unsigned char* >( aInitializationVector.getConstArray() ) ), aInitializationVector.getLength() };
46cdf0e10cSrcweir             xResult->m_pSecParam = PK11_ParamFromIV( nNSSCipherID, &aIVItem );
47cdf0e10cSrcweir             if ( xResult->m_pSecParam )
48cdf0e10cSrcweir             {
49cdf0e10cSrcweir                 xResult->m_pContext = PK11_CreateContextBySymKey( nNSSCipherID, bEncryption ? CKA_ENCRYPT : CKA_DECRYPT, xResult->m_pSymKey, xResult->m_pSecParam);
50cdf0e10cSrcweir                 if ( xResult->m_pContext )
51cdf0e10cSrcweir                 {
52cdf0e10cSrcweir                     xResult->m_bEncryption = bEncryption;
53cdf0e10cSrcweir                     xResult->m_bW3CPadding = bW3CPadding;
54cdf0e10cSrcweir                     xResult->m_bPadding = bW3CPadding || ( PK11_GetPadMechanism( nNSSCipherID ) == nNSSCipherID );
55cdf0e10cSrcweir                     xResult->m_nBlockSize = PK11_GetBlockSize( nNSSCipherID, xResult->m_pSecParam );
56cdf0e10cSrcweir                     if ( xResult->m_nBlockSize <= SAL_MAX_INT8 )
57cdf0e10cSrcweir                         return xResult.get();
58cdf0e10cSrcweir                 }
59cdf0e10cSrcweir             }
60cdf0e10cSrcweir         }
61cdf0e10cSrcweir     }
62cdf0e10cSrcweir 
63cdf0e10cSrcweir     return uno::Reference< xml::crypto::XCipherContext >();
64cdf0e10cSrcweir }
65cdf0e10cSrcweir 
66cdf0e10cSrcweir void OCipherContext::Dispose()
67cdf0e10cSrcweir {
68cdf0e10cSrcweir     ::osl::MutexGuard aGuard( m_aMutex );
69cdf0e10cSrcweir 
70cdf0e10cSrcweir     if ( m_pContext )
71cdf0e10cSrcweir     {
72cdf0e10cSrcweir         PK11_DestroyContext( m_pContext, PR_TRUE );
73cdf0e10cSrcweir         m_pContext = NULL;
74cdf0e10cSrcweir     }
75cdf0e10cSrcweir 
76cdf0e10cSrcweir     if ( m_pSecParam )
77cdf0e10cSrcweir     {
78cdf0e10cSrcweir         SECITEM_FreeItem( m_pSecParam, PR_TRUE );
79cdf0e10cSrcweir         m_pSecParam = NULL;
80cdf0e10cSrcweir     }
81cdf0e10cSrcweir 
82cdf0e10cSrcweir     if ( m_pSymKey )
83cdf0e10cSrcweir     {
84cdf0e10cSrcweir         PK11_FreeSymKey( m_pSymKey );
85cdf0e10cSrcweir         m_pSymKey = NULL;
86cdf0e10cSrcweir     }
87cdf0e10cSrcweir 
88cdf0e10cSrcweir     if ( m_pSlot )
89cdf0e10cSrcweir     {
90cdf0e10cSrcweir         PK11_FreeSlot( m_pSlot );
91cdf0e10cSrcweir         m_pSlot = NULL;
92cdf0e10cSrcweir     }
93cdf0e10cSrcweir 
94cdf0e10cSrcweir     m_bDisposed = true;
95cdf0e10cSrcweir }
96cdf0e10cSrcweir 
97cdf0e10cSrcweir uno::Sequence< ::sal_Int8 > SAL_CALL OCipherContext::convertWithCipherContext( const uno::Sequence< ::sal_Int8 >& aData )
98cdf0e10cSrcweir     throw ( lang::IllegalArgumentException, lang::DisposedException, uno::RuntimeException)
99cdf0e10cSrcweir {
100cdf0e10cSrcweir     ::osl::MutexGuard aGuard( m_aMutex );
101cdf0e10cSrcweir 
102cdf0e10cSrcweir     if ( m_bBroken )
103cdf0e10cSrcweir         throw uno::RuntimeException();
104cdf0e10cSrcweir 
105cdf0e10cSrcweir     if ( m_bDisposed )
106cdf0e10cSrcweir         throw lang::DisposedException();
107cdf0e10cSrcweir 
108cdf0e10cSrcweir     uno::Sequence< sal_Int8 > aToConvert;
109cdf0e10cSrcweir     if ( aData.getLength() )
110cdf0e10cSrcweir     {
111cdf0e10cSrcweir         sal_Int32 nOldLastBlockLen = m_aLastBlock.getLength();
112cdf0e10cSrcweir         OSL_ENSURE( nOldLastBlockLen <= m_nBlockSize, "Unexpected last block size!" );
113cdf0e10cSrcweir 
114cdf0e10cSrcweir         sal_Int32 nAvailableData = nOldLastBlockLen + aData.getLength();
115cdf0e10cSrcweir         sal_Int32 nToConvertLen = nAvailableData;
116cdf0e10cSrcweir         if ( m_bEncryption || !m_bW3CPadding )
117cdf0e10cSrcweir         {
118cdf0e10cSrcweir             if ( nAvailableData % m_nBlockSize == 0 )
119cdf0e10cSrcweir                 nToConvertLen = nAvailableData;
120cdf0e10cSrcweir             else if ( nAvailableData < m_nBlockSize )
121cdf0e10cSrcweir                 nToConvertLen = 0;
122cdf0e10cSrcweir             else
123cdf0e10cSrcweir                 nToConvertLen = nAvailableData - nAvailableData % m_nBlockSize;
124cdf0e10cSrcweir         }
125cdf0e10cSrcweir         else
126cdf0e10cSrcweir         {
127cdf0e10cSrcweir             // decryption with W3C padding needs at least one block for finalizing
128cdf0e10cSrcweir             if ( nAvailableData < m_nBlockSize * 2 )
129cdf0e10cSrcweir                 nToConvertLen = 0;
130cdf0e10cSrcweir             else
131cdf0e10cSrcweir                 nToConvertLen = nAvailableData - nAvailableData % m_nBlockSize - m_nBlockSize;
132cdf0e10cSrcweir         }
133cdf0e10cSrcweir 
134cdf0e10cSrcweir         aToConvert.realloc( nToConvertLen );
135cdf0e10cSrcweir         if ( nToConvertLen == 0 )
136cdf0e10cSrcweir         {
137cdf0e10cSrcweir             m_aLastBlock.realloc( nOldLastBlockLen + aData.getLength() );
138cdf0e10cSrcweir             rtl_copyMemory( m_aLastBlock.getArray() + nOldLastBlockLen, aData.getConstArray(), aData.getLength() );
139cdf0e10cSrcweir             // aToConvert stays empty
140cdf0e10cSrcweir         }
141cdf0e10cSrcweir         else if ( nToConvertLen < nOldLastBlockLen )
142cdf0e10cSrcweir         {
143cdf0e10cSrcweir             rtl_copyMemory( aToConvert.getArray(), m_aLastBlock.getConstArray(), nToConvertLen );
144cdf0e10cSrcweir             rtl_copyMemory( m_aLastBlock.getArray(), m_aLastBlock.getConstArray() + nToConvertLen, nOldLastBlockLen - nToConvertLen );
145cdf0e10cSrcweir             m_aLastBlock.realloc( nOldLastBlockLen - nToConvertLen + aData.getLength() );
146cdf0e10cSrcweir             rtl_copyMemory( m_aLastBlock.getArray() + nOldLastBlockLen - nToConvertLen, aData.getConstArray(), aData.getLength() );
147cdf0e10cSrcweir         }
148cdf0e10cSrcweir         else
149cdf0e10cSrcweir         {
150cdf0e10cSrcweir             rtl_copyMemory( aToConvert.getArray(), m_aLastBlock.getConstArray(), nOldLastBlockLen );
151cdf0e10cSrcweir             if ( nToConvertLen > nOldLastBlockLen )
152cdf0e10cSrcweir                 rtl_copyMemory( aToConvert.getArray() + nOldLastBlockLen, aData.getConstArray(), nToConvertLen - nOldLastBlockLen );
153cdf0e10cSrcweir             m_aLastBlock.realloc( nAvailableData - nToConvertLen );
154cdf0e10cSrcweir             rtl_copyMemory( m_aLastBlock.getArray(), aData.getConstArray() + nToConvertLen - nOldLastBlockLen, nAvailableData - nToConvertLen );
155cdf0e10cSrcweir         }
156cdf0e10cSrcweir     }
157cdf0e10cSrcweir 
158cdf0e10cSrcweir     uno::Sequence< sal_Int8 > aResult;
159cdf0e10cSrcweir     OSL_ENSURE( aToConvert.getLength() % m_nBlockSize == 0, "Unexpected size of the data to encrypt!" );
160cdf0e10cSrcweir     if ( aToConvert.getLength() )
161cdf0e10cSrcweir     {
162cdf0e10cSrcweir         int nResultLen = 0;
163cdf0e10cSrcweir         aResult.realloc( aToConvert.getLength() + m_nBlockSize );
164cdf0e10cSrcweir         if ( PK11_CipherOp( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() ), &nResultLen, aResult.getLength(), const_cast< unsigned char* >( reinterpret_cast< const unsigned char* >( aToConvert.getConstArray() ) ), aToConvert.getLength() ) != SECSuccess )
165cdf0e10cSrcweir         {
166cdf0e10cSrcweir             m_bBroken = true;
167cdf0e10cSrcweir             Dispose();
168cdf0e10cSrcweir             throw uno::RuntimeException();
169cdf0e10cSrcweir         }
170cdf0e10cSrcweir 
171cdf0e10cSrcweir         m_nConverted += aToConvert.getLength();
172cdf0e10cSrcweir         aResult.realloc( nResultLen );
173cdf0e10cSrcweir     }
174cdf0e10cSrcweir 
175cdf0e10cSrcweir     return aResult;
176cdf0e10cSrcweir }
177cdf0e10cSrcweir 
178cdf0e10cSrcweir uno::Sequence< ::sal_Int8 > SAL_CALL OCipherContext::finalizeCipherContextAndDispose()
179cdf0e10cSrcweir     throw (lang::DisposedException, uno::RuntimeException)
180cdf0e10cSrcweir {
181cdf0e10cSrcweir     ::osl::MutexGuard aGuard( m_aMutex );
182cdf0e10cSrcweir 
183cdf0e10cSrcweir     if ( m_bBroken )
184cdf0e10cSrcweir         throw uno::RuntimeException();
185cdf0e10cSrcweir 
186cdf0e10cSrcweir     if ( m_bDisposed )
187cdf0e10cSrcweir         throw lang::DisposedException();
188cdf0e10cSrcweir 
189cdf0e10cSrcweir     OSL_ENSURE( m_nBlockSize <= SAL_MAX_INT8, "Unexpected block size!" );
190cdf0e10cSrcweir     OSL_ENSURE( m_nConverted % m_nBlockSize == 0, "Unexpected amount of bytes is already converted!" );
191cdf0e10cSrcweir     sal_Int32 nSizeForPadding = ( m_nConverted + m_aLastBlock.getLength() ) % m_nBlockSize;
192cdf0e10cSrcweir 
193cdf0e10cSrcweir     // if it is decryption, the amount of data should be rounded to the block size even in case of padding
194cdf0e10cSrcweir     if ( ( !m_bPadding || !m_bEncryption ) && nSizeForPadding )
195cdf0e10cSrcweir         throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "The data should contain complete blocks only." ) ), uno::Reference< uno::XInterface >() );
196cdf0e10cSrcweir 
197cdf0e10cSrcweir     if ( m_bW3CPadding && m_bEncryption )
198cdf0e10cSrcweir     {
199cdf0e10cSrcweir         // in this case the last block should be smaller than standtard block
200cdf0e10cSrcweir         // it will be increased with the padding
201cdf0e10cSrcweir         OSL_ENSURE( m_aLastBlock.getLength() < m_nBlockSize, "Unexpected size of cashed incomplete last block!" );
202cdf0e10cSrcweir 
203cdf0e10cSrcweir         // W3CPadding handling for encryption
204cdf0e10cSrcweir         sal_Int32 nPaddingSize = m_nBlockSize - nSizeForPadding;
205cdf0e10cSrcweir         sal_Int32 nOldLastBlockLen = m_aLastBlock.getLength();
206cdf0e10cSrcweir         m_aLastBlock.realloc( nOldLastBlockLen + nPaddingSize );
207cdf0e10cSrcweir 
208cdf0e10cSrcweir         if ( nPaddingSize > 1 )
209cdf0e10cSrcweir         {
210cdf0e10cSrcweir             TimeValue aTime;
211cdf0e10cSrcweir             osl_getSystemTime( &aTime );
212cdf0e10cSrcweir             rtlRandomPool aRandomPool = rtl_random_createPool();
213cdf0e10cSrcweir             rtl_random_addBytes( aRandomPool, &aTime, 8 );
214cdf0e10cSrcweir             rtl_random_getBytes( aRandomPool, m_aLastBlock.getArray() + nOldLastBlockLen, nPaddingSize - 1 );
215cdf0e10cSrcweir             rtl_random_destroyPool ( aRandomPool );
216cdf0e10cSrcweir         }
217cdf0e10cSrcweir         m_aLastBlock[m_aLastBlock.getLength() - 1] = static_cast< sal_Int8 >( nPaddingSize );
218cdf0e10cSrcweir     }
219cdf0e10cSrcweir 
220cdf0e10cSrcweir     // finally should the last block be smaller than two standard blocks
221cdf0e10cSrcweir     OSL_ENSURE( m_aLastBlock.getLength() < m_nBlockSize * 2 , "Unexpected size of cashed incomplete last block!" );
222cdf0e10cSrcweir 
223cdf0e10cSrcweir     uno::Sequence< sal_Int8 > aResult;
224cdf0e10cSrcweir     if ( m_aLastBlock.getLength() )
225cdf0e10cSrcweir     {
226cdf0e10cSrcweir         int nPrefResLen = 0;
227cdf0e10cSrcweir         aResult.realloc( m_aLastBlock.getLength() + m_nBlockSize );
228cdf0e10cSrcweir         if ( PK11_CipherOp( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() ), &nPrefResLen, aResult.getLength(), const_cast< unsigned char* >( reinterpret_cast< const unsigned char* >( m_aLastBlock.getConstArray() ) ), m_aLastBlock.getLength() ) != SECSuccess )
229cdf0e10cSrcweir         {
230cdf0e10cSrcweir             m_bBroken = true;
231cdf0e10cSrcweir             Dispose();
232cdf0e10cSrcweir             throw uno::RuntimeException();
233cdf0e10cSrcweir         }
234cdf0e10cSrcweir 
235cdf0e10cSrcweir         aResult.realloc( nPrefResLen );
236cdf0e10cSrcweir         m_aLastBlock.realloc( 0 );
237cdf0e10cSrcweir     }
238cdf0e10cSrcweir 
239cdf0e10cSrcweir     sal_Int32 nPrefixLen = aResult.getLength();
240cdf0e10cSrcweir     aResult.realloc( nPrefixLen + m_nBlockSize * 2 );
241cdf0e10cSrcweir     unsigned nFinalLen = 0;
242cdf0e10cSrcweir     if ( PK11_DigestFinal( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() + nPrefixLen ), &nFinalLen, aResult.getLength() - nPrefixLen ) != SECSuccess )
243cdf0e10cSrcweir     {
244cdf0e10cSrcweir         m_bBroken = true;
245cdf0e10cSrcweir         Dispose();
246cdf0e10cSrcweir         throw uno::RuntimeException();
247cdf0e10cSrcweir     }
248cdf0e10cSrcweir 
249cdf0e10cSrcweir     aResult.realloc( nPrefixLen + nFinalLen );
250cdf0e10cSrcweir 
251cdf0e10cSrcweir     if ( m_bW3CPadding && !m_bEncryption )
252cdf0e10cSrcweir     {
253cdf0e10cSrcweir         // W3CPadding handling for decryption
254cdf0e10cSrcweir         // aResult should have anough data, since we let m_aLastBlock be big enough in case of decryption
255cdf0e10cSrcweir         OSL_ENSURE( aResult.getLength() >= m_nBlockSize, "Not enough data to handle the padding!" );
256cdf0e10cSrcweir 
257cdf0e10cSrcweir         sal_Int8 nBytesToRemove = aResult[aResult.getLength() - 1];
258cdf0e10cSrcweir         if ( nBytesToRemove <= 0 || nBytesToRemove > aResult.getLength() )
259cdf0e10cSrcweir         {
260cdf0e10cSrcweir             m_bBroken = true;
261cdf0e10cSrcweir             Dispose();
262cdf0e10cSrcweir             throw uno::RuntimeException();
263cdf0e10cSrcweir         }
264cdf0e10cSrcweir 
265cdf0e10cSrcweir         aResult.realloc( aResult.getLength() - nBytesToRemove );
266cdf0e10cSrcweir     }
267cdf0e10cSrcweir 
268cdf0e10cSrcweir     Dispose();
269cdf0e10cSrcweir 
270cdf0e10cSrcweir     return aResult;
271cdf0e10cSrcweir }
272cdf0e10cSrcweir 
273