Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | /* |
michael@0 | 5 | * This file manages object type indepentent functions. |
michael@0 | 6 | */ |
michael@0 | 7 | #include "seccomon.h" |
michael@0 | 8 | #include "secmod.h" |
michael@0 | 9 | #include "secmodi.h" |
michael@0 | 10 | #include "secmodti.h" |
michael@0 | 11 | #include "pkcs11.h" |
michael@0 | 12 | #include "pkcs11t.h" |
michael@0 | 13 | #include "pk11func.h" |
michael@0 | 14 | #include "key.h" |
michael@0 | 15 | #include "secitem.h" |
michael@0 | 16 | #include "secerr.h" |
michael@0 | 17 | #include "sslerr.h" |
michael@0 | 18 | |
michael@0 | 19 | #define PK11_SEARCH_CHUNKSIZE 10 |
michael@0 | 20 | |
michael@0 | 21 | /* |
michael@0 | 22 | * Build a block big enough to hold the data |
michael@0 | 23 | */ |
michael@0 | 24 | SECItem * |
michael@0 | 25 | PK11_BlockData(SECItem *data,unsigned long size) { |
michael@0 | 26 | SECItem *newData; |
michael@0 | 27 | |
michael@0 | 28 | newData = (SECItem *)PORT_Alloc(sizeof(SECItem)); |
michael@0 | 29 | if (newData == NULL) return NULL; |
michael@0 | 30 | |
michael@0 | 31 | newData->len = (data->len + (size-1))/size; |
michael@0 | 32 | newData->len *= size; |
michael@0 | 33 | |
michael@0 | 34 | newData->data = (unsigned char *) PORT_ZAlloc(newData->len); |
michael@0 | 35 | if (newData->data == NULL) { |
michael@0 | 36 | PORT_Free(newData); |
michael@0 | 37 | return NULL; |
michael@0 | 38 | } |
michael@0 | 39 | PORT_Memset(newData->data,newData->len-data->len,newData->len); |
michael@0 | 40 | PORT_Memcpy(newData->data,data->data,data->len); |
michael@0 | 41 | return newData; |
michael@0 | 42 | } |
michael@0 | 43 | |
michael@0 | 44 | |
michael@0 | 45 | SECStatus |
michael@0 | 46 | PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) { |
michael@0 | 47 | CK_RV crv; |
michael@0 | 48 | |
michael@0 | 49 | PK11_EnterSlotMonitor(slot); |
michael@0 | 50 | crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session,object); |
michael@0 | 51 | PK11_ExitSlotMonitor(slot); |
michael@0 | 52 | if (crv != CKR_OK) { |
michael@0 | 53 | return SECFailure; |
michael@0 | 54 | } |
michael@0 | 55 | return SECSuccess; |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | SECStatus |
michael@0 | 59 | PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) { |
michael@0 | 60 | CK_RV crv; |
michael@0 | 61 | SECStatus rv = SECSuccess; |
michael@0 | 62 | CK_SESSION_HANDLE rwsession; |
michael@0 | 63 | |
michael@0 | 64 | |
michael@0 | 65 | rwsession = PK11_GetRWSession(slot); |
michael@0 | 66 | if (rwsession == CK_INVALID_SESSION) { |
michael@0 | 67 | PORT_SetError(SEC_ERROR_BAD_DATA); |
michael@0 | 68 | return SECFailure; |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession,object); |
michael@0 | 72 | if (crv != CKR_OK) { |
michael@0 | 73 | rv = SECFailure; |
michael@0 | 74 | PORT_SetError(PK11_MapError(crv)); |
michael@0 | 75 | } |
michael@0 | 76 | PK11_RestoreROSession(slot,rwsession); |
michael@0 | 77 | return rv; |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | /* |
michael@0 | 81 | * Read in a single attribute into a SECItem. Allocate space for it with |
michael@0 | 82 | * PORT_Alloc unless an arena is supplied. In the latter case use the arena |
michael@0 | 83 | * to allocate the space. |
michael@0 | 84 | * |
michael@0 | 85 | * PK11_ReadAttribute sets the 'data' and 'len' fields of the SECItem but |
michael@0 | 86 | * does not modify its 'type' field. |
michael@0 | 87 | */ |
michael@0 | 88 | SECStatus |
michael@0 | 89 | PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, |
michael@0 | 90 | CK_ATTRIBUTE_TYPE type, PLArenaPool *arena, SECItem *result) { |
michael@0 | 91 | CK_ATTRIBUTE attr = { 0, NULL, 0 }; |
michael@0 | 92 | CK_RV crv; |
michael@0 | 93 | |
michael@0 | 94 | attr.type = type; |
michael@0 | 95 | |
michael@0 | 96 | PK11_EnterSlotMonitor(slot); |
michael@0 | 97 | crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); |
michael@0 | 98 | if (crv != CKR_OK) { |
michael@0 | 99 | PK11_ExitSlotMonitor(slot); |
michael@0 | 100 | PORT_SetError(PK11_MapError(crv)); |
michael@0 | 101 | return SECFailure; |
michael@0 | 102 | } |
michael@0 | 103 | if (arena) { |
michael@0 | 104 | attr.pValue = PORT_ArenaAlloc(arena,attr.ulValueLen); |
michael@0 | 105 | } else { |
michael@0 | 106 | attr.pValue = PORT_Alloc(attr.ulValueLen); |
michael@0 | 107 | } |
michael@0 | 108 | if (attr.pValue == NULL) { |
michael@0 | 109 | PK11_ExitSlotMonitor(slot); |
michael@0 | 110 | return SECFailure; |
michael@0 | 111 | } |
michael@0 | 112 | crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); |
michael@0 | 113 | PK11_ExitSlotMonitor(slot); |
michael@0 | 114 | if (crv != CKR_OK) { |
michael@0 | 115 | PORT_SetError(PK11_MapError(crv)); |
michael@0 | 116 | if (!arena) PORT_Free(attr.pValue); |
michael@0 | 117 | return SECFailure; |
michael@0 | 118 | } |
michael@0 | 119 | |
michael@0 | 120 | result->data = (unsigned char*)attr.pValue; |
michael@0 | 121 | result->len = attr.ulValueLen; |
michael@0 | 122 | |
michael@0 | 123 | return SECSuccess; |
michael@0 | 124 | } |
michael@0 | 125 | |
michael@0 | 126 | /* |
michael@0 | 127 | * Read in a single attribute into As a Ulong. |
michael@0 | 128 | */ |
michael@0 | 129 | CK_ULONG |
michael@0 | 130 | PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, |
michael@0 | 131 | CK_ATTRIBUTE_TYPE type) { |
michael@0 | 132 | CK_ATTRIBUTE attr; |
michael@0 | 133 | CK_ULONG value = CK_UNAVAILABLE_INFORMATION; |
michael@0 | 134 | CK_RV crv; |
michael@0 | 135 | |
michael@0 | 136 | PK11_SETATTRS(&attr,type,&value,sizeof(value)); |
michael@0 | 137 | |
michael@0 | 138 | PK11_EnterSlotMonitor(slot); |
michael@0 | 139 | crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); |
michael@0 | 140 | PK11_ExitSlotMonitor(slot); |
michael@0 | 141 | if (crv != CKR_OK) { |
michael@0 | 142 | PORT_SetError(PK11_MapError(crv)); |
michael@0 | 143 | } |
michael@0 | 144 | return value; |
michael@0 | 145 | } |
michael@0 | 146 | |
michael@0 | 147 | /* |
michael@0 | 148 | * check to see if a bool has been set. |
michael@0 | 149 | */ |
michael@0 | 150 | CK_BBOOL |
michael@0 | 151 | PK11_HasAttributeSet( PK11SlotInfo *slot, CK_OBJECT_HANDLE id, |
michael@0 | 152 | CK_ATTRIBUTE_TYPE type, PRBool haslock ) |
michael@0 | 153 | { |
michael@0 | 154 | CK_BBOOL ckvalue = CK_FALSE; |
michael@0 | 155 | CK_ATTRIBUTE theTemplate; |
michael@0 | 156 | CK_RV crv; |
michael@0 | 157 | |
michael@0 | 158 | /* Prepare to retrieve the attribute. */ |
michael@0 | 159 | PK11_SETATTRS( &theTemplate, type, &ckvalue, sizeof( CK_BBOOL ) ); |
michael@0 | 160 | |
michael@0 | 161 | /* Retrieve attribute value. */ |
michael@0 | 162 | if (!haslock) PK11_EnterSlotMonitor(slot); |
michael@0 | 163 | crv = PK11_GETTAB( slot )->C_GetAttributeValue( slot->session, id, |
michael@0 | 164 | &theTemplate, 1 ); |
michael@0 | 165 | if (!haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 166 | if( crv != CKR_OK ) { |
michael@0 | 167 | PORT_SetError( PK11_MapError( crv ) ); |
michael@0 | 168 | return CK_FALSE; |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | return ckvalue; |
michael@0 | 172 | } |
michael@0 | 173 | |
michael@0 | 174 | /* |
michael@0 | 175 | * returns a full list of attributes. Allocate space for them. If an arena is |
michael@0 | 176 | * provided, allocate space out of the arena. |
michael@0 | 177 | */ |
michael@0 | 178 | CK_RV |
michael@0 | 179 | PK11_GetAttributes(PLArenaPool *arena,PK11SlotInfo *slot, |
michael@0 | 180 | CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count) |
michael@0 | 181 | { |
michael@0 | 182 | int i; |
michael@0 | 183 | /* make pedantic happy... note that it's only used arena != NULL */ |
michael@0 | 184 | void *mark = NULL; |
michael@0 | 185 | CK_RV crv; |
michael@0 | 186 | PORT_Assert(slot->session != CK_INVALID_SESSION); |
michael@0 | 187 | if (slot->session == CK_INVALID_SESSION) |
michael@0 | 188 | return CKR_SESSION_HANDLE_INVALID; |
michael@0 | 189 | |
michael@0 | 190 | /* |
michael@0 | 191 | * first get all the lengths of the parameters. |
michael@0 | 192 | */ |
michael@0 | 193 | PK11_EnterSlotMonitor(slot); |
michael@0 | 194 | crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count); |
michael@0 | 195 | if (crv != CKR_OK) { |
michael@0 | 196 | PK11_ExitSlotMonitor(slot); |
michael@0 | 197 | return crv; |
michael@0 | 198 | } |
michael@0 | 199 | |
michael@0 | 200 | if (arena) { |
michael@0 | 201 | mark = PORT_ArenaMark(arena); |
michael@0 | 202 | if (mark == NULL) return CKR_HOST_MEMORY; |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | /* |
michael@0 | 206 | * now allocate space to store the results. |
michael@0 | 207 | */ |
michael@0 | 208 | for (i=0; i < count; i++) { |
michael@0 | 209 | if (attr[i].ulValueLen == 0) |
michael@0 | 210 | continue; |
michael@0 | 211 | if (arena) { |
michael@0 | 212 | attr[i].pValue = PORT_ArenaAlloc(arena,attr[i].ulValueLen); |
michael@0 | 213 | if (attr[i].pValue == NULL) { |
michael@0 | 214 | /* arena failures, just release the mark */ |
michael@0 | 215 | PORT_ArenaRelease(arena,mark); |
michael@0 | 216 | PK11_ExitSlotMonitor(slot); |
michael@0 | 217 | return CKR_HOST_MEMORY; |
michael@0 | 218 | } |
michael@0 | 219 | } else { |
michael@0 | 220 | attr[i].pValue = PORT_Alloc(attr[i].ulValueLen); |
michael@0 | 221 | if (attr[i].pValue == NULL) { |
michael@0 | 222 | /* Separate malloc failures, loop to release what we have |
michael@0 | 223 | * so far */ |
michael@0 | 224 | int j; |
michael@0 | 225 | for (j= 0; j < i; j++) { |
michael@0 | 226 | PORT_Free(attr[j].pValue); |
michael@0 | 227 | /* don't give the caller pointers to freed memory */ |
michael@0 | 228 | attr[j].pValue = NULL; |
michael@0 | 229 | } |
michael@0 | 230 | PK11_ExitSlotMonitor(slot); |
michael@0 | 231 | return CKR_HOST_MEMORY; |
michael@0 | 232 | } |
michael@0 | 233 | } |
michael@0 | 234 | } |
michael@0 | 235 | |
michael@0 | 236 | /* |
michael@0 | 237 | * finally get the results. |
michael@0 | 238 | */ |
michael@0 | 239 | crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count); |
michael@0 | 240 | PK11_ExitSlotMonitor(slot); |
michael@0 | 241 | if (crv != CKR_OK) { |
michael@0 | 242 | if (arena) { |
michael@0 | 243 | PORT_ArenaRelease(arena,mark); |
michael@0 | 244 | } else { |
michael@0 | 245 | for (i= 0; i < count; i++) { |
michael@0 | 246 | PORT_Free(attr[i].pValue); |
michael@0 | 247 | /* don't give the caller pointers to freed memory */ |
michael@0 | 248 | attr[i].pValue = NULL; |
michael@0 | 249 | } |
michael@0 | 250 | } |
michael@0 | 251 | } else if (arena && mark) { |
michael@0 | 252 | PORT_ArenaUnmark(arena,mark); |
michael@0 | 253 | } |
michael@0 | 254 | return crv; |
michael@0 | 255 | } |
michael@0 | 256 | |
michael@0 | 257 | PRBool |
michael@0 | 258 | PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) |
michael@0 | 259 | { |
michael@0 | 260 | return (PRBool) PK11_HasAttributeSet(slot, handle, CKA_TOKEN, PR_FALSE); |
michael@0 | 261 | } |
michael@0 | 262 | |
michael@0 | 263 | char * |
michael@0 | 264 | PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) |
michael@0 | 265 | { |
michael@0 | 266 | char *nickname = NULL; |
michael@0 | 267 | SECItem result; |
michael@0 | 268 | SECStatus rv; |
michael@0 | 269 | |
michael@0 | 270 | rv = PK11_ReadAttribute(slot,id,CKA_LABEL,NULL,&result); |
michael@0 | 271 | if (rv != SECSuccess) { |
michael@0 | 272 | return NULL; |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | nickname = PORT_ZAlloc(result.len+1); |
michael@0 | 276 | if (nickname == NULL) { |
michael@0 | 277 | PORT_Free(result.data); |
michael@0 | 278 | return NULL; |
michael@0 | 279 | } |
michael@0 | 280 | PORT_Memcpy(nickname, result.data, result.len); |
michael@0 | 281 | PORT_Free(result.data); |
michael@0 | 282 | return nickname; |
michael@0 | 283 | } |
michael@0 | 284 | |
michael@0 | 285 | SECStatus |
michael@0 | 286 | PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, |
michael@0 | 287 | const char *nickname) |
michael@0 | 288 | { |
michael@0 | 289 | int len = PORT_Strlen(nickname); |
michael@0 | 290 | CK_ATTRIBUTE setTemplate; |
michael@0 | 291 | CK_RV crv; |
michael@0 | 292 | CK_SESSION_HANDLE rwsession; |
michael@0 | 293 | |
michael@0 | 294 | if (len < 0) { |
michael@0 | 295 | return SECFailure; |
michael@0 | 296 | } |
michael@0 | 297 | |
michael@0 | 298 | PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *) nickname, len); |
michael@0 | 299 | rwsession = PK11_GetRWSession(slot); |
michael@0 | 300 | if (rwsession == CK_INVALID_SESSION) { |
michael@0 | 301 | PORT_SetError(SEC_ERROR_BAD_DATA); |
michael@0 | 302 | return SECFailure; |
michael@0 | 303 | } |
michael@0 | 304 | crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id, |
michael@0 | 305 | &setTemplate, 1); |
michael@0 | 306 | PK11_RestoreROSession(slot, rwsession); |
michael@0 | 307 | if (crv != CKR_OK) { |
michael@0 | 308 | PORT_SetError(PK11_MapError(crv)); |
michael@0 | 309 | return SECFailure; |
michael@0 | 310 | } |
michael@0 | 311 | return SECSuccess; |
michael@0 | 312 | } |
michael@0 | 313 | |
michael@0 | 314 | /* |
michael@0 | 315 | * strip leading zero's from key material |
michael@0 | 316 | */ |
michael@0 | 317 | void |
michael@0 | 318 | pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib) { |
michael@0 | 319 | char *ptr = (char *)attrib->pValue; |
michael@0 | 320 | unsigned long len = attrib->ulValueLen; |
michael@0 | 321 | |
michael@0 | 322 | while ((len > 1) && (*ptr == 0)) { |
michael@0 | 323 | len--; |
michael@0 | 324 | ptr++; |
michael@0 | 325 | } |
michael@0 | 326 | attrib->pValue = ptr; |
michael@0 | 327 | attrib->ulValueLen = len; |
michael@0 | 328 | } |
michael@0 | 329 | |
michael@0 | 330 | /* |
michael@0 | 331 | * get a new session on a slot. If we run out of session, use the slot's |
michael@0 | 332 | * 'exclusive' session. In this case owner becomes false. |
michael@0 | 333 | */ |
michael@0 | 334 | CK_SESSION_HANDLE |
michael@0 | 335 | pk11_GetNewSession(PK11SlotInfo *slot,PRBool *owner) |
michael@0 | 336 | { |
michael@0 | 337 | CK_SESSION_HANDLE session; |
michael@0 | 338 | *owner = PR_TRUE; |
michael@0 | 339 | if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); |
michael@0 | 340 | if ( PK11_GETTAB(slot)->C_OpenSession(slot->slotID,CKF_SERIAL_SESSION, |
michael@0 | 341 | slot,pk11_notify,&session) != CKR_OK) { |
michael@0 | 342 | *owner = PR_FALSE; |
michael@0 | 343 | session = slot->session; |
michael@0 | 344 | } |
michael@0 | 345 | if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); |
michael@0 | 346 | |
michael@0 | 347 | return session; |
michael@0 | 348 | } |
michael@0 | 349 | |
michael@0 | 350 | void |
michael@0 | 351 | pk11_CloseSession(PK11SlotInfo *slot,CK_SESSION_HANDLE session,PRBool owner) |
michael@0 | 352 | { |
michael@0 | 353 | if (!owner) return; |
michael@0 | 354 | if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); |
michael@0 | 355 | (void) PK11_GETTAB(slot)->C_CloseSession(session); |
michael@0 | 356 | if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); |
michael@0 | 357 | } |
michael@0 | 358 | |
michael@0 | 359 | |
michael@0 | 360 | SECStatus |
michael@0 | 361 | PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session, |
michael@0 | 362 | const CK_ATTRIBUTE *theTemplate, int count, |
michael@0 | 363 | PRBool token, CK_OBJECT_HANDLE *objectID) |
michael@0 | 364 | { |
michael@0 | 365 | CK_SESSION_HANDLE rwsession; |
michael@0 | 366 | CK_RV crv; |
michael@0 | 367 | SECStatus rv = SECSuccess; |
michael@0 | 368 | |
michael@0 | 369 | rwsession = session; |
michael@0 | 370 | if (token) { |
michael@0 | 371 | rwsession = PK11_GetRWSession(slot); |
michael@0 | 372 | } else if (rwsession == CK_INVALID_SESSION) { |
michael@0 | 373 | rwsession = slot->session; |
michael@0 | 374 | if (rwsession != CK_INVALID_SESSION) |
michael@0 | 375 | PK11_EnterSlotMonitor(slot); |
michael@0 | 376 | } |
michael@0 | 377 | if (rwsession == CK_INVALID_SESSION) { |
michael@0 | 378 | PORT_SetError(SEC_ERROR_BAD_DATA); |
michael@0 | 379 | return SECFailure; |
michael@0 | 380 | } |
michael@0 | 381 | crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, |
michael@0 | 382 | /* cast away const :-( */ (CK_ATTRIBUTE_PTR)theTemplate, |
michael@0 | 383 | count, objectID); |
michael@0 | 384 | if(crv != CKR_OK) { |
michael@0 | 385 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 386 | rv = SECFailure; |
michael@0 | 387 | } |
michael@0 | 388 | if (token) { |
michael@0 | 389 | PK11_RestoreROSession(slot, rwsession); |
michael@0 | 390 | } else if (session == CK_INVALID_SESSION) { |
michael@0 | 391 | PK11_ExitSlotMonitor(slot); |
michael@0 | 392 | } |
michael@0 | 393 | |
michael@0 | 394 | return rv; |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | |
michael@0 | 398 | /* This function may add a maximum of 9 attributes. */ |
michael@0 | 399 | unsigned int |
michael@0 | 400 | pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue) |
michael@0 | 401 | { |
michael@0 | 402 | |
michael@0 | 403 | const static CK_ATTRIBUTE_TYPE attrTypes[12] = { |
michael@0 | 404 | CKA_ENCRYPT, CKA_DECRYPT, 0 /* DIGEST */, CKA_SIGN, |
michael@0 | 405 | CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, 0 /* GEN */, |
michael@0 | 406 | 0 /* GEN PAIR */, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE |
michael@0 | 407 | }; |
michael@0 | 408 | |
michael@0 | 409 | const CK_ATTRIBUTE_TYPE *pType = attrTypes; |
michael@0 | 410 | CK_ATTRIBUTE *attr = attrs; |
michael@0 | 411 | CK_FLAGS test = CKF_ENCRYPT; |
michael@0 | 412 | |
michael@0 | 413 | |
michael@0 | 414 | PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS)); |
michael@0 | 415 | flags &= CKF_KEY_OPERATION_FLAGS; |
michael@0 | 416 | |
michael@0 | 417 | for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) { |
michael@0 | 418 | if (test & flags) { |
michael@0 | 419 | flags ^= test; |
michael@0 | 420 | PR_ASSERT(*pType); |
michael@0 | 421 | PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); |
michael@0 | 422 | ++attr; |
michael@0 | 423 | } |
michael@0 | 424 | } |
michael@0 | 425 | return (attr - attrs); |
michael@0 | 426 | } |
michael@0 | 427 | |
michael@0 | 428 | /* |
michael@0 | 429 | * Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE |
michael@0 | 430 | * and PK11_ATTR_PUBLIC are set. |
michael@0 | 431 | */ |
michael@0 | 432 | PRBool |
michael@0 | 433 | pk11_BadAttrFlags(PK11AttrFlags attrFlags) |
michael@0 | 434 | { |
michael@0 | 435 | PK11AttrFlags trueFlags = attrFlags & 0x55555555; |
michael@0 | 436 | PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555; |
michael@0 | 437 | return ((trueFlags & falseFlags) != 0); |
michael@0 | 438 | } |
michael@0 | 439 | |
michael@0 | 440 | /* |
michael@0 | 441 | * This function may add a maximum of 5 attributes. |
michael@0 | 442 | * The caller must make sure the attribute flags don't have conflicts. |
michael@0 | 443 | */ |
michael@0 | 444 | unsigned int |
michael@0 | 445 | pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs, |
michael@0 | 446 | CK_BBOOL *ckTrue, CK_BBOOL *ckFalse) |
michael@0 | 447 | { |
michael@0 | 448 | const static CK_ATTRIBUTE_TYPE attrTypes[5] = { |
michael@0 | 449 | CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE, |
michael@0 | 450 | CKA_EXTRACTABLE |
michael@0 | 451 | }; |
michael@0 | 452 | |
michael@0 | 453 | const CK_ATTRIBUTE_TYPE *pType = attrTypes; |
michael@0 | 454 | CK_ATTRIBUTE *attr = attrs; |
michael@0 | 455 | PK11AttrFlags test = PK11_ATTR_TOKEN; |
michael@0 | 456 | |
michael@0 | 457 | PR_ASSERT(!pk11_BadAttrFlags(attrFlags)); |
michael@0 | 458 | |
michael@0 | 459 | /* we test two related bitflags in each iteration */ |
michael@0 | 460 | for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) { |
michael@0 | 461 | if (test & attrFlags) { |
michael@0 | 462 | attrFlags ^= test; |
michael@0 | 463 | PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); |
michael@0 | 464 | ++attr; |
michael@0 | 465 | } else if ((test << 1) & attrFlags) { |
michael@0 | 466 | attrFlags ^= (test << 1); |
michael@0 | 467 | PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse); |
michael@0 | 468 | ++attr; |
michael@0 | 469 | } |
michael@0 | 470 | } |
michael@0 | 471 | return (attr - attrs); |
michael@0 | 472 | } |
michael@0 | 473 | |
michael@0 | 474 | /* |
michael@0 | 475 | * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually |
michael@0 | 476 | * set up a signature to get the signaure length. |
michael@0 | 477 | */ |
michael@0 | 478 | static int |
michael@0 | 479 | pk11_backupGetSignLength(SECKEYPrivateKey *key) |
michael@0 | 480 | { |
michael@0 | 481 | PK11SlotInfo *slot = key->pkcs11Slot; |
michael@0 | 482 | CK_MECHANISM mech = {0, NULL, 0 }; |
michael@0 | 483 | PRBool owner = PR_TRUE; |
michael@0 | 484 | CK_SESSION_HANDLE session; |
michael@0 | 485 | CK_ULONG len; |
michael@0 | 486 | CK_RV crv; |
michael@0 | 487 | unsigned char h_data[20] = { 0 }; |
michael@0 | 488 | unsigned char buf[20]; /* obviously to small */ |
michael@0 | 489 | CK_ULONG smallLen = sizeof(buf); |
michael@0 | 490 | |
michael@0 | 491 | mech.mechanism = PK11_MapSignKeyType(key->keyType); |
michael@0 | 492 | |
michael@0 | 493 | session = pk11_GetNewSession(slot,&owner); |
michael@0 | 494 | if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); |
michael@0 | 495 | crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID); |
michael@0 | 496 | if (crv != CKR_OK) { |
michael@0 | 497 | if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); |
michael@0 | 498 | pk11_CloseSession(slot,session,owner); |
michael@0 | 499 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 500 | return -1; |
michael@0 | 501 | } |
michael@0 | 502 | len = 0; |
michael@0 | 503 | crv = PK11_GETTAB(slot)->C_Sign(session,h_data,sizeof(h_data), |
michael@0 | 504 | NULL, &len); |
michael@0 | 505 | /* now call C_Sign with too small a buffer to clear the session state */ |
michael@0 | 506 | (void) PK11_GETTAB(slot)-> |
michael@0 | 507 | C_Sign(session,h_data,sizeof(h_data),buf,&smallLen); |
michael@0 | 508 | |
michael@0 | 509 | if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); |
michael@0 | 510 | pk11_CloseSession(slot,session,owner); |
michael@0 | 511 | if (crv != CKR_OK) { |
michael@0 | 512 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 513 | return -1; |
michael@0 | 514 | } |
michael@0 | 515 | return len; |
michael@0 | 516 | } |
michael@0 | 517 | |
michael@0 | 518 | /* |
michael@0 | 519 | * get the length of a signature object based on the key |
michael@0 | 520 | */ |
michael@0 | 521 | int |
michael@0 | 522 | PK11_SignatureLen(SECKEYPrivateKey *key) |
michael@0 | 523 | { |
michael@0 | 524 | int val; |
michael@0 | 525 | SECItem attributeItem = {siBuffer, NULL, 0}; |
michael@0 | 526 | SECStatus rv; |
michael@0 | 527 | int length; |
michael@0 | 528 | |
michael@0 | 529 | switch (key->keyType) { |
michael@0 | 530 | case rsaKey: |
michael@0 | 531 | val = PK11_GetPrivateModulusLen(key); |
michael@0 | 532 | if (val == -1) { |
michael@0 | 533 | return pk11_backupGetSignLength(key); |
michael@0 | 534 | } |
michael@0 | 535 | return (unsigned long) val; |
michael@0 | 536 | |
michael@0 | 537 | case fortezzaKey: |
michael@0 | 538 | return 40; |
michael@0 | 539 | |
michael@0 | 540 | case dsaKey: |
michael@0 | 541 | rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_SUBPRIME, |
michael@0 | 542 | NULL, &attributeItem); |
michael@0 | 543 | if (rv == SECSuccess) { |
michael@0 | 544 | length = attributeItem.len; |
michael@0 | 545 | if ((length > 0) && attributeItem.data[0] == 0) { |
michael@0 | 546 | length--; |
michael@0 | 547 | } |
michael@0 | 548 | PORT_Free(attributeItem.data); |
michael@0 | 549 | return length*2; |
michael@0 | 550 | } |
michael@0 | 551 | return pk11_backupGetSignLength(key); |
michael@0 | 552 | |
michael@0 | 553 | case ecKey: |
michael@0 | 554 | rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_EC_PARAMS, |
michael@0 | 555 | NULL, &attributeItem); |
michael@0 | 556 | if (rv == SECSuccess) { |
michael@0 | 557 | length = SECKEY_ECParamsToBasePointOrderLen(&attributeItem); |
michael@0 | 558 | PORT_Free(attributeItem.data); |
michael@0 | 559 | if (length != 0) { |
michael@0 | 560 | length = ((length + 7)/8) * 2; |
michael@0 | 561 | return length; |
michael@0 | 562 | } |
michael@0 | 563 | } |
michael@0 | 564 | return pk11_backupGetSignLength(key); |
michael@0 | 565 | default: |
michael@0 | 566 | break; |
michael@0 | 567 | } |
michael@0 | 568 | PORT_SetError( SEC_ERROR_INVALID_KEY ); |
michael@0 | 569 | return 0; |
michael@0 | 570 | } |
michael@0 | 571 | |
michael@0 | 572 | /* |
michael@0 | 573 | * copy a key (or any other object) on a token |
michael@0 | 574 | */ |
michael@0 | 575 | CK_OBJECT_HANDLE |
michael@0 | 576 | PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject) |
michael@0 | 577 | { |
michael@0 | 578 | CK_OBJECT_HANDLE destObject; |
michael@0 | 579 | CK_RV crv; |
michael@0 | 580 | |
michael@0 | 581 | PK11_EnterSlotMonitor(slot); |
michael@0 | 582 | crv = PK11_GETTAB(slot)->C_CopyObject(slot->session,srcObject,NULL,0, |
michael@0 | 583 | &destObject); |
michael@0 | 584 | PK11_ExitSlotMonitor(slot); |
michael@0 | 585 | if (crv == CKR_OK) return destObject; |
michael@0 | 586 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 587 | return CK_INVALID_HANDLE; |
michael@0 | 588 | } |
michael@0 | 589 | |
michael@0 | 590 | PRBool |
michael@0 | 591 | pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs, |
michael@0 | 592 | CK_ATTRIBUTE_TYPE target) |
michael@0 | 593 | { |
michael@0 | 594 | for (; numAttrs > 0; ++attr, --numAttrs) { |
michael@0 | 595 | if (attr->type == target) |
michael@0 | 596 | return PR_TRUE; |
michael@0 | 597 | } |
michael@0 | 598 | return PR_FALSE; |
michael@0 | 599 | } |
michael@0 | 600 | |
michael@0 | 601 | /* |
michael@0 | 602 | * Recover the Signed data. We need this because our old verify can't |
michael@0 | 603 | * figure out which hash algorithm to use until we decryptted this. |
michael@0 | 604 | */ |
michael@0 | 605 | SECStatus |
michael@0 | 606 | PK11_VerifyRecover(SECKEYPublicKey *key, const SECItem *sig, |
michael@0 | 607 | SECItem *dsig, void *wincx) |
michael@0 | 608 | { |
michael@0 | 609 | PK11SlotInfo *slot = key->pkcs11Slot; |
michael@0 | 610 | CK_OBJECT_HANDLE id = key->pkcs11ID; |
michael@0 | 611 | CK_MECHANISM mech = {0, NULL, 0 }; |
michael@0 | 612 | PRBool owner = PR_TRUE; |
michael@0 | 613 | CK_SESSION_HANDLE session; |
michael@0 | 614 | CK_ULONG len; |
michael@0 | 615 | CK_RV crv; |
michael@0 | 616 | |
michael@0 | 617 | mech.mechanism = PK11_MapSignKeyType(key->keyType); |
michael@0 | 618 | |
michael@0 | 619 | if (slot == NULL) { |
michael@0 | 620 | slot = PK11_GetBestSlotWithAttributes(mech.mechanism, |
michael@0 | 621 | CKF_VERIFY_RECOVER,0,wincx); |
michael@0 | 622 | if (slot == NULL) { |
michael@0 | 623 | PORT_SetError( SEC_ERROR_NO_MODULE ); |
michael@0 | 624 | return SECFailure; |
michael@0 | 625 | } |
michael@0 | 626 | id = PK11_ImportPublicKey(slot,key,PR_FALSE); |
michael@0 | 627 | } else { |
michael@0 | 628 | PK11_ReferenceSlot(slot); |
michael@0 | 629 | } |
michael@0 | 630 | |
michael@0 | 631 | if (id == CK_INVALID_HANDLE) { |
michael@0 | 632 | PK11_FreeSlot(slot); |
michael@0 | 633 | PORT_SetError( SEC_ERROR_BAD_KEY ); |
michael@0 | 634 | return SECFailure; |
michael@0 | 635 | } |
michael@0 | 636 | |
michael@0 | 637 | session = pk11_GetNewSession(slot,&owner); |
michael@0 | 638 | if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); |
michael@0 | 639 | crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session,&mech,id); |
michael@0 | 640 | if (crv != CKR_OK) { |
michael@0 | 641 | if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); |
michael@0 | 642 | pk11_CloseSession(slot,session,owner); |
michael@0 | 643 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 644 | PK11_FreeSlot(slot); |
michael@0 | 645 | return SECFailure; |
michael@0 | 646 | } |
michael@0 | 647 | len = dsig->len; |
michael@0 | 648 | crv = PK11_GETTAB(slot)->C_VerifyRecover(session,sig->data, |
michael@0 | 649 | sig->len, dsig->data, &len); |
michael@0 | 650 | if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); |
michael@0 | 651 | pk11_CloseSession(slot,session,owner); |
michael@0 | 652 | dsig->len = len; |
michael@0 | 653 | if (crv != CKR_OK) { |
michael@0 | 654 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 655 | PK11_FreeSlot(slot); |
michael@0 | 656 | return SECFailure; |
michael@0 | 657 | } |
michael@0 | 658 | PK11_FreeSlot(slot); |
michael@0 | 659 | return SECSuccess; |
michael@0 | 660 | } |
michael@0 | 661 | |
michael@0 | 662 | /* |
michael@0 | 663 | * verify a signature from its hash. |
michael@0 | 664 | */ |
michael@0 | 665 | SECStatus |
michael@0 | 666 | PK11_Verify(SECKEYPublicKey *key, const SECItem *sig, const SECItem *hash, |
michael@0 | 667 | void *wincx) |
michael@0 | 668 | { |
michael@0 | 669 | PK11SlotInfo *slot = key->pkcs11Slot; |
michael@0 | 670 | CK_OBJECT_HANDLE id = key->pkcs11ID; |
michael@0 | 671 | CK_MECHANISM mech = {0, NULL, 0 }; |
michael@0 | 672 | PRBool owner = PR_TRUE; |
michael@0 | 673 | CK_SESSION_HANDLE session; |
michael@0 | 674 | CK_RV crv; |
michael@0 | 675 | |
michael@0 | 676 | mech.mechanism = PK11_MapSignKeyType(key->keyType); |
michael@0 | 677 | |
michael@0 | 678 | if (slot == NULL) { |
michael@0 | 679 | unsigned int length = 0; |
michael@0 | 680 | if ((mech.mechanism == CKM_DSA) && |
michael@0 | 681 | /* 129 is 1024 bits translated to bytes and |
michael@0 | 682 | * padded with an optional '0' to maintain a |
michael@0 | 683 | * positive sign */ |
michael@0 | 684 | (key->u.dsa.params.prime.len > 129)) { |
michael@0 | 685 | /* we need to get a slot that not only can do DSA, but can do DSA2 |
michael@0 | 686 | * key lengths */ |
michael@0 | 687 | length = key->u.dsa.params.prime.len; |
michael@0 | 688 | if (key->u.dsa.params.prime.data[0] == 0) { |
michael@0 | 689 | length --; |
michael@0 | 690 | } |
michael@0 | 691 | /* convert keysize to bits for slot lookup */ |
michael@0 | 692 | length *= 8; |
michael@0 | 693 | } |
michael@0 | 694 | slot = PK11_GetBestSlotWithAttributes(mech.mechanism, |
michael@0 | 695 | CKF_VERIFY,length,wincx); |
michael@0 | 696 | if (slot == NULL) { |
michael@0 | 697 | PORT_SetError( SEC_ERROR_NO_MODULE ); |
michael@0 | 698 | return SECFailure; |
michael@0 | 699 | } |
michael@0 | 700 | id = PK11_ImportPublicKey(slot,key,PR_FALSE); |
michael@0 | 701 | |
michael@0 | 702 | } else { |
michael@0 | 703 | PK11_ReferenceSlot(slot); |
michael@0 | 704 | } |
michael@0 | 705 | |
michael@0 | 706 | if (id == CK_INVALID_HANDLE) { |
michael@0 | 707 | PK11_FreeSlot(slot); |
michael@0 | 708 | PORT_SetError( SEC_ERROR_BAD_KEY ); |
michael@0 | 709 | return SECFailure; |
michael@0 | 710 | } |
michael@0 | 711 | |
michael@0 | 712 | session = pk11_GetNewSession(slot,&owner); |
michael@0 | 713 | if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); |
michael@0 | 714 | crv = PK11_GETTAB(slot)->C_VerifyInit(session,&mech,id); |
michael@0 | 715 | if (crv != CKR_OK) { |
michael@0 | 716 | if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); |
michael@0 | 717 | pk11_CloseSession(slot,session,owner); |
michael@0 | 718 | PK11_FreeSlot(slot); |
michael@0 | 719 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 720 | return SECFailure; |
michael@0 | 721 | } |
michael@0 | 722 | crv = PK11_GETTAB(slot)->C_Verify(session,hash->data, |
michael@0 | 723 | hash->len, sig->data, sig->len); |
michael@0 | 724 | if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); |
michael@0 | 725 | pk11_CloseSession(slot,session,owner); |
michael@0 | 726 | PK11_FreeSlot(slot); |
michael@0 | 727 | if (crv != CKR_OK) { |
michael@0 | 728 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 729 | return SECFailure; |
michael@0 | 730 | } |
michael@0 | 731 | return SECSuccess; |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | /* |
michael@0 | 735 | * sign a hash. The algorithm is determined by the key. |
michael@0 | 736 | */ |
michael@0 | 737 | SECStatus |
michael@0 | 738 | PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, const SECItem *hash) |
michael@0 | 739 | { |
michael@0 | 740 | PK11SlotInfo *slot = key->pkcs11Slot; |
michael@0 | 741 | CK_MECHANISM mech = {0, NULL, 0 }; |
michael@0 | 742 | PRBool owner = PR_TRUE; |
michael@0 | 743 | CK_SESSION_HANDLE session; |
michael@0 | 744 | PRBool haslock = PR_FALSE; |
michael@0 | 745 | CK_ULONG len; |
michael@0 | 746 | CK_RV crv; |
michael@0 | 747 | |
michael@0 | 748 | mech.mechanism = PK11_MapSignKeyType(key->keyType); |
michael@0 | 749 | |
michael@0 | 750 | if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) { |
michael@0 | 751 | PK11_HandlePasswordCheck(slot, key->wincx); |
michael@0 | 752 | } |
michael@0 | 753 | |
michael@0 | 754 | session = pk11_GetNewSession(slot,&owner); |
michael@0 | 755 | haslock = (!owner || !(slot->isThreadSafe)); |
michael@0 | 756 | if (haslock) PK11_EnterSlotMonitor(slot); |
michael@0 | 757 | crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID); |
michael@0 | 758 | if (crv != CKR_OK) { |
michael@0 | 759 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 760 | pk11_CloseSession(slot,session,owner); |
michael@0 | 761 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 762 | return SECFailure; |
michael@0 | 763 | } |
michael@0 | 764 | |
michael@0 | 765 | /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then |
michael@0 | 766 | * do C_Login with CKU_CONTEXT_SPECIFIC |
michael@0 | 767 | * between C_SignInit and C_Sign */ |
michael@0 | 768 | if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) { |
michael@0 | 769 | PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE); |
michael@0 | 770 | } |
michael@0 | 771 | |
michael@0 | 772 | len = sig->len; |
michael@0 | 773 | crv = PK11_GETTAB(slot)->C_Sign(session,hash->data, |
michael@0 | 774 | hash->len, sig->data, &len); |
michael@0 | 775 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 776 | pk11_CloseSession(slot,session,owner); |
michael@0 | 777 | sig->len = len; |
michael@0 | 778 | if (crv != CKR_OK) { |
michael@0 | 779 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 780 | return SECFailure; |
michael@0 | 781 | } |
michael@0 | 782 | return SECSuccess; |
michael@0 | 783 | } |
michael@0 | 784 | |
michael@0 | 785 | /* |
michael@0 | 786 | * sign data with a MAC key. |
michael@0 | 787 | */ |
michael@0 | 788 | SECStatus |
michael@0 | 789 | PK11_SignWithSymKey(PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism, |
michael@0 | 790 | SECItem *param, SECItem *sig, const SECItem *data) |
michael@0 | 791 | { |
michael@0 | 792 | PK11SlotInfo *slot = symKey->slot; |
michael@0 | 793 | CK_MECHANISM mech = {0, NULL, 0 }; |
michael@0 | 794 | PRBool owner = PR_TRUE; |
michael@0 | 795 | CK_SESSION_HANDLE session; |
michael@0 | 796 | PRBool haslock = PR_FALSE; |
michael@0 | 797 | CK_ULONG len; |
michael@0 | 798 | CK_RV crv; |
michael@0 | 799 | |
michael@0 | 800 | mech.mechanism = mechanism; |
michael@0 | 801 | if (param) { |
michael@0 | 802 | mech.pParameter = param->data; |
michael@0 | 803 | mech.ulParameterLen = param->len; |
michael@0 | 804 | } |
michael@0 | 805 | |
michael@0 | 806 | session = pk11_GetNewSession(slot,&owner); |
michael@0 | 807 | haslock = (!owner || !(slot->isThreadSafe)); |
michael@0 | 808 | if (haslock) PK11_EnterSlotMonitor(slot); |
michael@0 | 809 | crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,symKey->objectID); |
michael@0 | 810 | if (crv != CKR_OK) { |
michael@0 | 811 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 812 | pk11_CloseSession(slot,session,owner); |
michael@0 | 813 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 814 | return SECFailure; |
michael@0 | 815 | } |
michael@0 | 816 | |
michael@0 | 817 | len = sig->len; |
michael@0 | 818 | crv = PK11_GETTAB(slot)->C_Sign(session,data->data, |
michael@0 | 819 | data->len, sig->data, &len); |
michael@0 | 820 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 821 | pk11_CloseSession(slot,session,owner); |
michael@0 | 822 | sig->len = len; |
michael@0 | 823 | if (crv != CKR_OK) { |
michael@0 | 824 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 825 | return SECFailure; |
michael@0 | 826 | } |
michael@0 | 827 | return SECSuccess; |
michael@0 | 828 | } |
michael@0 | 829 | |
michael@0 | 830 | SECStatus |
michael@0 | 831 | PK11_Decrypt(PK11SymKey *symKey, |
michael@0 | 832 | CK_MECHANISM_TYPE mechanism, SECItem *param, |
michael@0 | 833 | unsigned char *out, unsigned int *outLen, |
michael@0 | 834 | unsigned int maxLen, |
michael@0 | 835 | const unsigned char *enc, unsigned encLen) |
michael@0 | 836 | { |
michael@0 | 837 | PK11SlotInfo *slot = symKey->slot; |
michael@0 | 838 | CK_MECHANISM mech = {0, NULL, 0 }; |
michael@0 | 839 | CK_ULONG len = maxLen; |
michael@0 | 840 | PRBool owner = PR_TRUE; |
michael@0 | 841 | CK_SESSION_HANDLE session; |
michael@0 | 842 | PRBool haslock = PR_FALSE; |
michael@0 | 843 | CK_RV crv; |
michael@0 | 844 | |
michael@0 | 845 | mech.mechanism = mechanism; |
michael@0 | 846 | if (param) { |
michael@0 | 847 | mech.pParameter = param->data; |
michael@0 | 848 | mech.ulParameterLen = param->len; |
michael@0 | 849 | } |
michael@0 | 850 | |
michael@0 | 851 | session = pk11_GetNewSession(slot, &owner); |
michael@0 | 852 | haslock = (!owner || !slot->isThreadSafe); |
michael@0 | 853 | if (haslock) PK11_EnterSlotMonitor(slot); |
michael@0 | 854 | crv = PK11_GETTAB(slot)->C_DecryptInit(session, &mech, symKey->objectID); |
michael@0 | 855 | if (crv != CKR_OK) { |
michael@0 | 856 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 857 | pk11_CloseSession(slot, session, owner); |
michael@0 | 858 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 859 | return SECFailure; |
michael@0 | 860 | } |
michael@0 | 861 | |
michael@0 | 862 | crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen, |
michael@0 | 863 | out, &len); |
michael@0 | 864 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 865 | pk11_CloseSession(slot, session, owner); |
michael@0 | 866 | *outLen = len; |
michael@0 | 867 | if (crv != CKR_OK) { |
michael@0 | 868 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 869 | return SECFailure; |
michael@0 | 870 | } |
michael@0 | 871 | return SECSuccess; |
michael@0 | 872 | } |
michael@0 | 873 | |
michael@0 | 874 | SECStatus |
michael@0 | 875 | PK11_Encrypt(PK11SymKey *symKey, |
michael@0 | 876 | CK_MECHANISM_TYPE mechanism, SECItem *param, |
michael@0 | 877 | unsigned char *out, unsigned int *outLen, |
michael@0 | 878 | unsigned int maxLen, |
michael@0 | 879 | const unsigned char *data, unsigned int dataLen) |
michael@0 | 880 | { |
michael@0 | 881 | PK11SlotInfo *slot = symKey->slot; |
michael@0 | 882 | CK_MECHANISM mech = {0, NULL, 0 }; |
michael@0 | 883 | CK_ULONG len = maxLen; |
michael@0 | 884 | PRBool owner = PR_TRUE; |
michael@0 | 885 | CK_SESSION_HANDLE session; |
michael@0 | 886 | PRBool haslock = PR_FALSE; |
michael@0 | 887 | CK_RV crv; |
michael@0 | 888 | |
michael@0 | 889 | mech.mechanism = mechanism; |
michael@0 | 890 | if (param) { |
michael@0 | 891 | mech.pParameter = param->data; |
michael@0 | 892 | mech.ulParameterLen = param->len; |
michael@0 | 893 | } |
michael@0 | 894 | |
michael@0 | 895 | session = pk11_GetNewSession(slot, &owner); |
michael@0 | 896 | haslock = (!owner || !slot->isThreadSafe); |
michael@0 | 897 | if (haslock) PK11_EnterSlotMonitor(slot); |
michael@0 | 898 | crv = PK11_GETTAB(slot)->C_EncryptInit(session, &mech, symKey->objectID); |
michael@0 | 899 | if (crv != CKR_OK) { |
michael@0 | 900 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 901 | pk11_CloseSession(slot,session,owner); |
michael@0 | 902 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 903 | return SECFailure; |
michael@0 | 904 | } |
michael@0 | 905 | crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data, |
michael@0 | 906 | dataLen, out, &len); |
michael@0 | 907 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 908 | pk11_CloseSession(slot,session,owner); |
michael@0 | 909 | *outLen = len; |
michael@0 | 910 | if (crv != CKR_OK) { |
michael@0 | 911 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 912 | return SECFailure; |
michael@0 | 913 | } |
michael@0 | 914 | return SECSuccess; |
michael@0 | 915 | } |
michael@0 | 916 | |
michael@0 | 917 | static SECStatus |
michael@0 | 918 | pk11_PrivDecryptRaw(SECKEYPrivateKey *key, |
michael@0 | 919 | unsigned char *data, unsigned *outLen, unsigned int maxLen, |
michael@0 | 920 | const unsigned char *enc, unsigned encLen, |
michael@0 | 921 | CK_MECHANISM_PTR mech) |
michael@0 | 922 | { |
michael@0 | 923 | PK11SlotInfo *slot = key->pkcs11Slot; |
michael@0 | 924 | CK_ULONG out = maxLen; |
michael@0 | 925 | PRBool owner = PR_TRUE; |
michael@0 | 926 | CK_SESSION_HANDLE session; |
michael@0 | 927 | PRBool haslock = PR_FALSE; |
michael@0 | 928 | CK_RV crv; |
michael@0 | 929 | |
michael@0 | 930 | if (key->keyType != rsaKey) { |
michael@0 | 931 | PORT_SetError( SEC_ERROR_INVALID_KEY ); |
michael@0 | 932 | return SECFailure; |
michael@0 | 933 | } |
michael@0 | 934 | |
michael@0 | 935 | /* Why do we do a PK11_handle check here? for simple |
michael@0 | 936 | * decryption? .. because the user may have asked for 'ask always' |
michael@0 | 937 | * and this is a private key operation. In practice, thought, it's mute |
michael@0 | 938 | * since only servers wind up using this function */ |
michael@0 | 939 | if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) { |
michael@0 | 940 | PK11_HandlePasswordCheck(slot, key->wincx); |
michael@0 | 941 | } |
michael@0 | 942 | session = pk11_GetNewSession(slot,&owner); |
michael@0 | 943 | haslock = (!owner || !(slot->isThreadSafe)); |
michael@0 | 944 | if (haslock) PK11_EnterSlotMonitor(slot); |
michael@0 | 945 | crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, key->pkcs11ID); |
michael@0 | 946 | if (crv != CKR_OK) { |
michael@0 | 947 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 948 | pk11_CloseSession(slot,session,owner); |
michael@0 | 949 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 950 | return SECFailure; |
michael@0 | 951 | } |
michael@0 | 952 | |
michael@0 | 953 | /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then |
michael@0 | 954 | * do C_Login with CKU_CONTEXT_SPECIFIC |
michael@0 | 955 | * between C_DecryptInit and C_Decrypt |
michael@0 | 956 | * ... But see note above about servers */ |
michael@0 | 957 | if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) { |
michael@0 | 958 | PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE); |
michael@0 | 959 | } |
michael@0 | 960 | |
michael@0 | 961 | crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen, |
michael@0 | 962 | data, &out); |
michael@0 | 963 | if (haslock) PK11_ExitSlotMonitor(slot); |
michael@0 | 964 | pk11_CloseSession(slot,session,owner); |
michael@0 | 965 | *outLen = out; |
michael@0 | 966 | if (crv != CKR_OK) { |
michael@0 | 967 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 968 | return SECFailure; |
michael@0 | 969 | } |
michael@0 | 970 | return SECSuccess; |
michael@0 | 971 | } |
michael@0 | 972 | |
michael@0 | 973 | SECStatus |
michael@0 | 974 | PK11_PubDecryptRaw(SECKEYPrivateKey *key, |
michael@0 | 975 | unsigned char *data, unsigned *outLen, unsigned int maxLen, |
michael@0 | 976 | const unsigned char *enc, unsigned encLen) |
michael@0 | 977 | { |
michael@0 | 978 | CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 }; |
michael@0 | 979 | return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech); |
michael@0 | 980 | } |
michael@0 | 981 | |
michael@0 | 982 | SECStatus |
michael@0 | 983 | PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key, |
michael@0 | 984 | unsigned char *data, unsigned *outLen, unsigned int maxLen, |
michael@0 | 985 | const unsigned char *enc, unsigned encLen) |
michael@0 | 986 | { |
michael@0 | 987 | CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 }; |
michael@0 | 988 | return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech); |
michael@0 | 989 | } |
michael@0 | 990 | |
michael@0 | 991 | static SECStatus |
michael@0 | 992 | pk11_PubEncryptRaw(SECKEYPublicKey *key, |
michael@0 | 993 | unsigned char *out, unsigned int *outLen, |
michael@0 | 994 | unsigned int maxLen, |
michael@0 | 995 | const unsigned char *data, unsigned dataLen, |
michael@0 | 996 | CK_MECHANISM_PTR mech, void *wincx) |
michael@0 | 997 | { |
michael@0 | 998 | PK11SlotInfo *slot; |
michael@0 | 999 | CK_OBJECT_HANDLE id; |
michael@0 | 1000 | CK_ULONG len = maxLen; |
michael@0 | 1001 | PRBool owner = PR_TRUE; |
michael@0 | 1002 | CK_SESSION_HANDLE session; |
michael@0 | 1003 | CK_RV crv; |
michael@0 | 1004 | |
michael@0 | 1005 | slot = PK11_GetBestSlotWithAttributes(mech->mechanism,CKF_ENCRYPT,0,wincx); |
michael@0 | 1006 | if (slot == NULL) { |
michael@0 | 1007 | PORT_SetError( SEC_ERROR_NO_MODULE ); |
michael@0 | 1008 | return SECFailure; |
michael@0 | 1009 | } |
michael@0 | 1010 | |
michael@0 | 1011 | id = PK11_ImportPublicKey(slot,key,PR_FALSE); |
michael@0 | 1012 | |
michael@0 | 1013 | if (id == CK_INVALID_HANDLE) { |
michael@0 | 1014 | PK11_FreeSlot(slot); |
michael@0 | 1015 | PORT_SetError( SEC_ERROR_BAD_KEY ); |
michael@0 | 1016 | return SECFailure; |
michael@0 | 1017 | } |
michael@0 | 1018 | |
michael@0 | 1019 | session = pk11_GetNewSession(slot,&owner); |
michael@0 | 1020 | if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); |
michael@0 | 1021 | crv = PK11_GETTAB(slot)->C_EncryptInit(session, mech, id); |
michael@0 | 1022 | if (crv != CKR_OK) { |
michael@0 | 1023 | if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); |
michael@0 | 1024 | pk11_CloseSession(slot,session,owner); |
michael@0 | 1025 | PK11_FreeSlot(slot); |
michael@0 | 1026 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1027 | return SECFailure; |
michael@0 | 1028 | } |
michael@0 | 1029 | crv = PK11_GETTAB(slot)->C_Encrypt(session,(unsigned char *)data,dataLen, |
michael@0 | 1030 | out,&len); |
michael@0 | 1031 | if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); |
michael@0 | 1032 | pk11_CloseSession(slot,session,owner); |
michael@0 | 1033 | PK11_FreeSlot(slot); |
michael@0 | 1034 | *outLen = len; |
michael@0 | 1035 | if (crv != CKR_OK) { |
michael@0 | 1036 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1037 | return SECFailure; |
michael@0 | 1038 | } |
michael@0 | 1039 | return SECSuccess; |
michael@0 | 1040 | } |
michael@0 | 1041 | |
michael@0 | 1042 | SECStatus |
michael@0 | 1043 | PK11_PubEncryptRaw(SECKEYPublicKey *key, |
michael@0 | 1044 | unsigned char *enc, |
michael@0 | 1045 | const unsigned char *data, unsigned dataLen, |
michael@0 | 1046 | void *wincx) |
michael@0 | 1047 | { |
michael@0 | 1048 | CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 }; |
michael@0 | 1049 | unsigned int outLen; |
michael@0 | 1050 | if (!key || key->keyType != rsaKey) { |
michael@0 | 1051 | PORT_SetError(SEC_ERROR_BAD_KEY); |
michael@0 | 1052 | return SECFailure; |
michael@0 | 1053 | } |
michael@0 | 1054 | outLen = SECKEY_PublicKeyStrength(key); |
michael@0 | 1055 | return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech, |
michael@0 | 1056 | wincx); |
michael@0 | 1057 | } |
michael@0 | 1058 | |
michael@0 | 1059 | SECStatus |
michael@0 | 1060 | PK11_PubEncryptPKCS1(SECKEYPublicKey *key, |
michael@0 | 1061 | unsigned char *enc, |
michael@0 | 1062 | const unsigned char *data, unsigned dataLen, |
michael@0 | 1063 | void *wincx) |
michael@0 | 1064 | { |
michael@0 | 1065 | CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 }; |
michael@0 | 1066 | unsigned int outLen; |
michael@0 | 1067 | if (!key || key->keyType != rsaKey) { |
michael@0 | 1068 | PORT_SetError(SEC_ERROR_BAD_KEY); |
michael@0 | 1069 | return SECFailure; |
michael@0 | 1070 | } |
michael@0 | 1071 | outLen = SECKEY_PublicKeyStrength(key); |
michael@0 | 1072 | return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech, |
michael@0 | 1073 | wincx); |
michael@0 | 1074 | } |
michael@0 | 1075 | |
michael@0 | 1076 | SECStatus |
michael@0 | 1077 | PK11_PrivDecrypt(SECKEYPrivateKey *key, |
michael@0 | 1078 | CK_MECHANISM_TYPE mechanism, SECItem *param, |
michael@0 | 1079 | unsigned char *out, unsigned int *outLen, |
michael@0 | 1080 | unsigned int maxLen, |
michael@0 | 1081 | const unsigned char *enc, unsigned encLen) |
michael@0 | 1082 | { |
michael@0 | 1083 | CK_MECHANISM mech = { mechanism, NULL, 0 }; |
michael@0 | 1084 | if (param) { |
michael@0 | 1085 | mech.pParameter = param->data; |
michael@0 | 1086 | mech.ulParameterLen = param->len; |
michael@0 | 1087 | } |
michael@0 | 1088 | return pk11_PrivDecryptRaw(key, out, outLen, maxLen, enc, encLen, &mech); |
michael@0 | 1089 | } |
michael@0 | 1090 | |
michael@0 | 1091 | SECStatus |
michael@0 | 1092 | PK11_PubEncrypt(SECKEYPublicKey *key, |
michael@0 | 1093 | CK_MECHANISM_TYPE mechanism, SECItem *param, |
michael@0 | 1094 | unsigned char *out, unsigned int *outLen, |
michael@0 | 1095 | unsigned int maxLen, |
michael@0 | 1096 | const unsigned char *data, unsigned dataLen, |
michael@0 | 1097 | void *wincx) |
michael@0 | 1098 | { |
michael@0 | 1099 | CK_MECHANISM mech = { mechanism, NULL, 0 }; |
michael@0 | 1100 | if (param) { |
michael@0 | 1101 | mech.pParameter = param->data; |
michael@0 | 1102 | mech.ulParameterLen = param->len; |
michael@0 | 1103 | } |
michael@0 | 1104 | return pk11_PubEncryptRaw(key, out, outLen, maxLen, data, dataLen, &mech, |
michael@0 | 1105 | wincx); |
michael@0 | 1106 | } |
michael@0 | 1107 | |
michael@0 | 1108 | SECKEYPrivateKey * |
michael@0 | 1109 | PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, |
michael@0 | 1110 | CK_MECHANISM_TYPE wrapType, SECItem *param, |
michael@0 | 1111 | SECItem *wrappedKey, SECItem *label, |
michael@0 | 1112 | SECItem *idValue, PRBool perm, PRBool sensitive, |
michael@0 | 1113 | CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage, |
michael@0 | 1114 | int usageCount, void *wincx) |
michael@0 | 1115 | { |
michael@0 | 1116 | CK_BBOOL cktrue = CK_TRUE; |
michael@0 | 1117 | CK_BBOOL ckfalse = CK_FALSE; |
michael@0 | 1118 | CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; |
michael@0 | 1119 | CK_ATTRIBUTE keyTemplate[15] ; |
michael@0 | 1120 | int templateCount = 0; |
michael@0 | 1121 | CK_OBJECT_HANDLE privKeyID; |
michael@0 | 1122 | CK_MECHANISM mechanism; |
michael@0 | 1123 | CK_ATTRIBUTE *attrs = keyTemplate; |
michael@0 | 1124 | SECItem *param_free = NULL, *ck_id = NULL; |
michael@0 | 1125 | CK_RV crv; |
michael@0 | 1126 | CK_SESSION_HANDLE rwsession; |
michael@0 | 1127 | PK11SymKey *newKey = NULL; |
michael@0 | 1128 | int i; |
michael@0 | 1129 | |
michael@0 | 1130 | if(!slot || !wrappedKey || !idValue) { |
michael@0 | 1131 | /* SET AN ERROR!!! */ |
michael@0 | 1132 | return NULL; |
michael@0 | 1133 | } |
michael@0 | 1134 | |
michael@0 | 1135 | ck_id = PK11_MakeIDFromPubKey(idValue); |
michael@0 | 1136 | if(!ck_id) { |
michael@0 | 1137 | return NULL; |
michael@0 | 1138 | } |
michael@0 | 1139 | |
michael@0 | 1140 | PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse, |
michael@0 | 1141 | sizeof(cktrue)); attrs++; |
michael@0 | 1142 | PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++; |
michael@0 | 1143 | PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++; |
michael@0 | 1144 | PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse, |
michael@0 | 1145 | sizeof(cktrue)); attrs++; |
michael@0 | 1146 | PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse, |
michael@0 | 1147 | sizeof(cktrue)); attrs++; |
michael@0 | 1148 | if (label && label->data) { |
michael@0 | 1149 | PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len); attrs++; |
michael@0 | 1150 | } |
michael@0 | 1151 | PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++; |
michael@0 | 1152 | for (i=0; i < usageCount; i++) { |
michael@0 | 1153 | PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue)); attrs++; |
michael@0 | 1154 | } |
michael@0 | 1155 | |
michael@0 | 1156 | if (PK11_IsInternal(slot)) { |
michael@0 | 1157 | PK11_SETATTRS(attrs, CKA_NETSCAPE_DB, idValue->data, |
michael@0 | 1158 | idValue->len); attrs++; |
michael@0 | 1159 | } |
michael@0 | 1160 | |
michael@0 | 1161 | templateCount = attrs - keyTemplate; |
michael@0 | 1162 | PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)) ); |
michael@0 | 1163 | |
michael@0 | 1164 | mechanism.mechanism = wrapType; |
michael@0 | 1165 | if(!param) param = param_free= PK11_ParamFromIV(wrapType, NULL); |
michael@0 | 1166 | if(param) { |
michael@0 | 1167 | mechanism.pParameter = param->data; |
michael@0 | 1168 | mechanism.ulParameterLen = param->len; |
michael@0 | 1169 | } else { |
michael@0 | 1170 | mechanism.pParameter = NULL; |
michael@0 | 1171 | mechanism.ulParameterLen = 0; |
michael@0 | 1172 | } |
michael@0 | 1173 | |
michael@0 | 1174 | if (wrappingKey->slot != slot) { |
michael@0 | 1175 | newKey = pk11_CopyToSlot(slot,wrapType,CKA_UNWRAP,wrappingKey); |
michael@0 | 1176 | } else { |
michael@0 | 1177 | newKey = PK11_ReferenceSymKey(wrappingKey); |
michael@0 | 1178 | } |
michael@0 | 1179 | |
michael@0 | 1180 | if (newKey) { |
michael@0 | 1181 | if (perm) { |
michael@0 | 1182 | /* Get RW Session will either lock the monitor if necessary, |
michael@0 | 1183 | * or return a thread safe session handle, or fail. */ |
michael@0 | 1184 | rwsession = PK11_GetRWSession(slot); |
michael@0 | 1185 | } else { |
michael@0 | 1186 | rwsession = slot->session; |
michael@0 | 1187 | if (rwsession != CK_INVALID_SESSION) |
michael@0 | 1188 | PK11_EnterSlotMonitor(slot); |
michael@0 | 1189 | } |
michael@0 | 1190 | /* This is a lot a work to deal with fussy PKCS #11 modules |
michael@0 | 1191 | * that can't bother to return BAD_DATA when presented with an |
michael@0 | 1192 | * invalid session! */ |
michael@0 | 1193 | if (rwsession == CK_INVALID_SESSION) { |
michael@0 | 1194 | PORT_SetError(SEC_ERROR_BAD_DATA); |
michael@0 | 1195 | goto loser; |
michael@0 | 1196 | } |
michael@0 | 1197 | crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism, |
michael@0 | 1198 | newKey->objectID, |
michael@0 | 1199 | wrappedKey->data, |
michael@0 | 1200 | wrappedKey->len, keyTemplate, |
michael@0 | 1201 | templateCount, &privKeyID); |
michael@0 | 1202 | |
michael@0 | 1203 | if (perm) { |
michael@0 | 1204 | PK11_RestoreROSession(slot, rwsession); |
michael@0 | 1205 | } else { |
michael@0 | 1206 | PK11_ExitSlotMonitor(slot); |
michael@0 | 1207 | } |
michael@0 | 1208 | PK11_FreeSymKey(newKey); |
michael@0 | 1209 | newKey = NULL; |
michael@0 | 1210 | } else { |
michael@0 | 1211 | crv = CKR_FUNCTION_NOT_SUPPORTED; |
michael@0 | 1212 | } |
michael@0 | 1213 | |
michael@0 | 1214 | if (ck_id) { |
michael@0 | 1215 | SECITEM_FreeItem(ck_id, PR_TRUE); |
michael@0 | 1216 | ck_id = NULL; |
michael@0 | 1217 | } |
michael@0 | 1218 | |
michael@0 | 1219 | if (crv != CKR_OK) { |
michael@0 | 1220 | /* we couldn't unwrap the key, use the internal module to do the |
michael@0 | 1221 | * unwrap, then load the new key into the token */ |
michael@0 | 1222 | PK11SlotInfo *int_slot = PK11_GetInternalSlot(); |
michael@0 | 1223 | |
michael@0 | 1224 | if (int_slot && (slot != int_slot)) { |
michael@0 | 1225 | SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot, |
michael@0 | 1226 | wrappingKey, wrapType, param, wrappedKey, label, |
michael@0 | 1227 | idValue, PR_FALSE, PR_FALSE, |
michael@0 | 1228 | keyType, usage, usageCount, wincx); |
michael@0 | 1229 | if (privKey) { |
michael@0 | 1230 | SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot,privKey, |
michael@0 | 1231 | NULL,perm,sensitive); |
michael@0 | 1232 | SECKEY_DestroyPrivateKey(privKey); |
michael@0 | 1233 | PK11_FreeSlot(int_slot); |
michael@0 | 1234 | return newPrivKey; |
michael@0 | 1235 | } |
michael@0 | 1236 | } |
michael@0 | 1237 | if (int_slot) PK11_FreeSlot(int_slot); |
michael@0 | 1238 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1239 | return NULL; |
michael@0 | 1240 | } |
michael@0 | 1241 | return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx); |
michael@0 | 1242 | |
michael@0 | 1243 | loser: |
michael@0 | 1244 | if (newKey) { |
michael@0 | 1245 | PK11_FreeSymKey(newKey); |
michael@0 | 1246 | } |
michael@0 | 1247 | if (ck_id) { |
michael@0 | 1248 | SECITEM_FreeItem(ck_id, PR_TRUE); |
michael@0 | 1249 | } |
michael@0 | 1250 | return NULL; |
michael@0 | 1251 | } |
michael@0 | 1252 | |
michael@0 | 1253 | /* |
michael@0 | 1254 | * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey |
michael@0 | 1255 | * The strategy is to get both keys to reside in the same slot, |
michael@0 | 1256 | * one that can perform the desired crypto mechanism and then |
michael@0 | 1257 | * call C_WrapKey after all the setup has taken place. |
michael@0 | 1258 | */ |
michael@0 | 1259 | SECStatus |
michael@0 | 1260 | PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, |
michael@0 | 1261 | SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType, |
michael@0 | 1262 | SECItem *param, SECItem *wrappedKey, void *wincx) |
michael@0 | 1263 | { |
michael@0 | 1264 | PK11SlotInfo *privSlot = privKey->pkcs11Slot; /* The slot where |
michael@0 | 1265 | * the private key |
michael@0 | 1266 | * we are going to |
michael@0 | 1267 | * wrap lives. |
michael@0 | 1268 | */ |
michael@0 | 1269 | PK11SymKey *newSymKey = NULL; |
michael@0 | 1270 | SECKEYPrivateKey *newPrivKey = NULL; |
michael@0 | 1271 | SECItem *param_free = NULL; |
michael@0 | 1272 | CK_ULONG len = wrappedKey->len; |
michael@0 | 1273 | CK_MECHANISM mech; |
michael@0 | 1274 | CK_RV crv; |
michael@0 | 1275 | |
michael@0 | 1276 | if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) { |
michael@0 | 1277 | /* Figure out a slot that does the mechanism and try to import |
michael@0 | 1278 | * the private key onto that slot. |
michael@0 | 1279 | */ |
michael@0 | 1280 | PK11SlotInfo *int_slot = PK11_GetInternalSlot(); |
michael@0 | 1281 | |
michael@0 | 1282 | privSlot = int_slot; /* The private key has a new home */ |
michael@0 | 1283 | newPrivKey = PK11_LoadPrivKey(privSlot,privKey,NULL,PR_FALSE,PR_FALSE); |
michael@0 | 1284 | /* newPrivKey has allocated its own reference to the slot, so it's |
michael@0 | 1285 | * safe until we destroy newPrivkey. |
michael@0 | 1286 | */ |
michael@0 | 1287 | PK11_FreeSlot(int_slot); |
michael@0 | 1288 | if (newPrivKey == NULL) { |
michael@0 | 1289 | return SECFailure; |
michael@0 | 1290 | } |
michael@0 | 1291 | privKey = newPrivKey; |
michael@0 | 1292 | } |
michael@0 | 1293 | |
michael@0 | 1294 | if (privSlot != wrappingKey->slot) { |
michael@0 | 1295 | newSymKey = pk11_CopyToSlot (privSlot, wrapType, CKA_WRAP, |
michael@0 | 1296 | wrappingKey); |
michael@0 | 1297 | wrappingKey = newSymKey; |
michael@0 | 1298 | } |
michael@0 | 1299 | |
michael@0 | 1300 | if (wrappingKey == NULL) { |
michael@0 | 1301 | if (newPrivKey) { |
michael@0 | 1302 | SECKEY_DestroyPrivateKey(newPrivKey); |
michael@0 | 1303 | } |
michael@0 | 1304 | return SECFailure; |
michael@0 | 1305 | } |
michael@0 | 1306 | mech.mechanism = wrapType; |
michael@0 | 1307 | if (!param) { |
michael@0 | 1308 | param = param_free = PK11_ParamFromIV(wrapType, NULL); |
michael@0 | 1309 | } |
michael@0 | 1310 | if (param) { |
michael@0 | 1311 | mech.pParameter = param->data; |
michael@0 | 1312 | mech.ulParameterLen = param->len; |
michael@0 | 1313 | } else { |
michael@0 | 1314 | mech.pParameter = NULL; |
michael@0 | 1315 | mech.ulParameterLen = 0; |
michael@0 | 1316 | } |
michael@0 | 1317 | |
michael@0 | 1318 | PK11_EnterSlotMonitor(privSlot); |
michael@0 | 1319 | crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech, |
michael@0 | 1320 | wrappingKey->objectID, |
michael@0 | 1321 | privKey->pkcs11ID, |
michael@0 | 1322 | wrappedKey->data, &len); |
michael@0 | 1323 | PK11_ExitSlotMonitor(privSlot); |
michael@0 | 1324 | |
michael@0 | 1325 | if (newSymKey) { |
michael@0 | 1326 | PK11_FreeSymKey(newSymKey); |
michael@0 | 1327 | } |
michael@0 | 1328 | if (newPrivKey) { |
michael@0 | 1329 | SECKEY_DestroyPrivateKey(newPrivKey); |
michael@0 | 1330 | } |
michael@0 | 1331 | if (param_free) { |
michael@0 | 1332 | SECITEM_FreeItem(param_free,PR_TRUE); |
michael@0 | 1333 | } |
michael@0 | 1334 | |
michael@0 | 1335 | if (crv != CKR_OK) { |
michael@0 | 1336 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1337 | return SECFailure; |
michael@0 | 1338 | } |
michael@0 | 1339 | |
michael@0 | 1340 | wrappedKey->len = len; |
michael@0 | 1341 | return SECSuccess; |
michael@0 | 1342 | } |
michael@0 | 1343 | |
michael@0 | 1344 | #if 0 |
michael@0 | 1345 | /* |
michael@0 | 1346 | * Sample code relating to linked list returned by PK11_FindGenericObjects |
michael@0 | 1347 | */ |
michael@0 | 1348 | |
michael@0 | 1349 | /* |
michael@0 | 1350 | * You can walk the list with the following code: |
michael@0 | 1351 | */ |
michael@0 | 1352 | firstObj = PK11_FindGenericObjects(slot, objClass); |
michael@0 | 1353 | for (thisObj=firstObj; |
michael@0 | 1354 | thisObj; |
michael@0 | 1355 | thisObj=PK11_GetNextGenericObject(thisObj)) { |
michael@0 | 1356 | /* operate on thisObj */ |
michael@0 | 1357 | } |
michael@0 | 1358 | /* |
michael@0 | 1359 | * If you want a particular object from the list... |
michael@0 | 1360 | */ |
michael@0 | 1361 | firstObj = PK11_FindGenericObjects(slot, objClass); |
michael@0 | 1362 | for (thisObj=firstObj; |
michael@0 | 1363 | thisObj; |
michael@0 | 1364 | thisObj=PK11_GetNextGenericObject(thisObj)) { |
michael@0 | 1365 | if (isMyObj(thisObj)) { |
michael@0 | 1366 | if ( thisObj == firstObj) { |
michael@0 | 1367 | /* NOTE: firstObj could be NULL at this point */ |
michael@0 | 1368 | firstObj = PK11_GetNextGenericObject(thsObj); |
michael@0 | 1369 | } |
michael@0 | 1370 | PK11_UnlinkGenericObject(thisObj); |
michael@0 | 1371 | myObj = thisObj; |
michael@0 | 1372 | break; |
michael@0 | 1373 | } |
michael@0 | 1374 | } |
michael@0 | 1375 | |
michael@0 | 1376 | PK11_DestroyGenericObjects(firstObj); |
michael@0 | 1377 | |
michael@0 | 1378 | /* use myObj */ |
michael@0 | 1379 | |
michael@0 | 1380 | PK11_DestroyGenericObject(myObj); |
michael@0 | 1381 | #endif /* sample code */ |
michael@0 | 1382 | |
michael@0 | 1383 | /* |
michael@0 | 1384 | * return a linked, non-circular list of generic objects. |
michael@0 | 1385 | * If you are only interested |
michael@0 | 1386 | * in one object, just use the first object in the list. To find the |
michael@0 | 1387 | * rest of the list use PK11_GetNextGenericObject() to return the next object. |
michael@0 | 1388 | */ |
michael@0 | 1389 | PK11GenericObject * |
michael@0 | 1390 | PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass) |
michael@0 | 1391 | { |
michael@0 | 1392 | CK_ATTRIBUTE template[1]; |
michael@0 | 1393 | CK_ATTRIBUTE *attrs = template; |
michael@0 | 1394 | CK_OBJECT_HANDLE *objectIDs = NULL; |
michael@0 | 1395 | PK11GenericObject *lastObj = NULL, *obj; |
michael@0 | 1396 | PK11GenericObject *firstObj = NULL; |
michael@0 | 1397 | int i, count = 0; |
michael@0 | 1398 | |
michael@0 | 1399 | |
michael@0 | 1400 | PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++; |
michael@0 | 1401 | |
michael@0 | 1402 | objectIDs = pk11_FindObjectsByTemplate(slot,template,1,&count); |
michael@0 | 1403 | if (objectIDs == NULL) { |
michael@0 | 1404 | return NULL; |
michael@0 | 1405 | } |
michael@0 | 1406 | |
michael@0 | 1407 | /* where we connect our object once we've created it.. */ |
michael@0 | 1408 | for (i=0; i < count; i++) { |
michael@0 | 1409 | obj = PORT_New(PK11GenericObject); |
michael@0 | 1410 | if ( !obj ) { |
michael@0 | 1411 | if (firstObj) { |
michael@0 | 1412 | PK11_DestroyGenericObjects(firstObj); |
michael@0 | 1413 | } |
michael@0 | 1414 | PORT_Free(objectIDs); |
michael@0 | 1415 | return NULL; |
michael@0 | 1416 | } |
michael@0 | 1417 | /* initialize it */ |
michael@0 | 1418 | obj->slot = PK11_ReferenceSlot(slot); |
michael@0 | 1419 | obj->objectID = objectIDs[i]; |
michael@0 | 1420 | obj->next = NULL; |
michael@0 | 1421 | obj->prev = NULL; |
michael@0 | 1422 | |
michael@0 | 1423 | /* link it in */ |
michael@0 | 1424 | if (firstObj == NULL) { |
michael@0 | 1425 | firstObj = obj; |
michael@0 | 1426 | } else { |
michael@0 | 1427 | PK11_LinkGenericObject(lastObj, obj); |
michael@0 | 1428 | } |
michael@0 | 1429 | lastObj = obj; |
michael@0 | 1430 | } |
michael@0 | 1431 | PORT_Free(objectIDs); |
michael@0 | 1432 | return firstObj; |
michael@0 | 1433 | } |
michael@0 | 1434 | |
michael@0 | 1435 | /* |
michael@0 | 1436 | * get the Next Object in the list. |
michael@0 | 1437 | */ |
michael@0 | 1438 | PK11GenericObject * |
michael@0 | 1439 | PK11_GetNextGenericObject(PK11GenericObject *object) |
michael@0 | 1440 | { |
michael@0 | 1441 | return object->next; |
michael@0 | 1442 | } |
michael@0 | 1443 | |
michael@0 | 1444 | PK11GenericObject * |
michael@0 | 1445 | PK11_GetPrevGenericObject(PK11GenericObject *object) |
michael@0 | 1446 | { |
michael@0 | 1447 | return object->prev; |
michael@0 | 1448 | } |
michael@0 | 1449 | |
michael@0 | 1450 | /* |
michael@0 | 1451 | * Link a single object into a new list. |
michael@0 | 1452 | * if the object is already in another list, remove it first. |
michael@0 | 1453 | */ |
michael@0 | 1454 | SECStatus |
michael@0 | 1455 | PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object) |
michael@0 | 1456 | { |
michael@0 | 1457 | PK11_UnlinkGenericObject(object); |
michael@0 | 1458 | object->prev = list; |
michael@0 | 1459 | object->next = list->next; |
michael@0 | 1460 | list->next = object; |
michael@0 | 1461 | if (object->next != NULL) { |
michael@0 | 1462 | object->next->prev = object; |
michael@0 | 1463 | } |
michael@0 | 1464 | return SECSuccess; |
michael@0 | 1465 | } |
michael@0 | 1466 | |
michael@0 | 1467 | /* |
michael@0 | 1468 | * remove an object from the list. If the object isn't already in |
michael@0 | 1469 | * a list unlink becomes a noop. |
michael@0 | 1470 | */ |
michael@0 | 1471 | SECStatus |
michael@0 | 1472 | PK11_UnlinkGenericObject(PK11GenericObject *object) |
michael@0 | 1473 | { |
michael@0 | 1474 | if (object->prev != NULL) { |
michael@0 | 1475 | object->prev->next = object->next; |
michael@0 | 1476 | } |
michael@0 | 1477 | if (object->next != NULL) { |
michael@0 | 1478 | object->next->prev = object->prev; |
michael@0 | 1479 | } |
michael@0 | 1480 | |
michael@0 | 1481 | object->next = NULL; |
michael@0 | 1482 | object->prev = NULL; |
michael@0 | 1483 | return SECSuccess; |
michael@0 | 1484 | } |
michael@0 | 1485 | |
michael@0 | 1486 | /* |
michael@0 | 1487 | * This function removes a single object from the list and destroys it. |
michael@0 | 1488 | * For an already unlinked object there is no difference between |
michael@0 | 1489 | * PK11_DestroyGenericObject and PK11_DestroyGenericObjects |
michael@0 | 1490 | */ |
michael@0 | 1491 | SECStatus |
michael@0 | 1492 | PK11_DestroyGenericObject(PK11GenericObject *object) |
michael@0 | 1493 | { |
michael@0 | 1494 | if (object == NULL) { |
michael@0 | 1495 | return SECSuccess; |
michael@0 | 1496 | } |
michael@0 | 1497 | |
michael@0 | 1498 | PK11_UnlinkGenericObject(object); |
michael@0 | 1499 | if (object->slot) { |
michael@0 | 1500 | PK11_FreeSlot(object->slot); |
michael@0 | 1501 | } |
michael@0 | 1502 | PORT_Free(object); |
michael@0 | 1503 | return SECSuccess; |
michael@0 | 1504 | } |
michael@0 | 1505 | |
michael@0 | 1506 | /* |
michael@0 | 1507 | * walk down a link list of generic objects destroying them. |
michael@0 | 1508 | * This will destroy all objects in a list that the object is linked into. |
michael@0 | 1509 | * (the list is traversed in both directions). |
michael@0 | 1510 | */ |
michael@0 | 1511 | SECStatus |
michael@0 | 1512 | PK11_DestroyGenericObjects(PK11GenericObject *objects) |
michael@0 | 1513 | { |
michael@0 | 1514 | PK11GenericObject *nextObject; |
michael@0 | 1515 | PK11GenericObject *prevObject; |
michael@0 | 1516 | |
michael@0 | 1517 | if (objects == NULL) { |
michael@0 | 1518 | return SECSuccess; |
michael@0 | 1519 | } |
michael@0 | 1520 | |
michael@0 | 1521 | nextObject = objects->next; |
michael@0 | 1522 | prevObject = objects->prev; |
michael@0 | 1523 | |
michael@0 | 1524 | /* delete all the objects after it in the list */ |
michael@0 | 1525 | for (; objects; objects = nextObject) { |
michael@0 | 1526 | nextObject = objects->next; |
michael@0 | 1527 | PK11_DestroyGenericObject(objects); |
michael@0 | 1528 | } |
michael@0 | 1529 | /* delete all the objects before it in the list */ |
michael@0 | 1530 | for (objects = prevObject; objects; objects = prevObject) { |
michael@0 | 1531 | prevObject = objects->prev; |
michael@0 | 1532 | PK11_DestroyGenericObject(objects); |
michael@0 | 1533 | } |
michael@0 | 1534 | return SECSuccess; |
michael@0 | 1535 | } |
michael@0 | 1536 | |
michael@0 | 1537 | |
michael@0 | 1538 | /* |
michael@0 | 1539 | * Hand Create a new object and return the Generic object for our new object. |
michael@0 | 1540 | */ |
michael@0 | 1541 | PK11GenericObject * |
michael@0 | 1542 | PK11_CreateGenericObject(PK11SlotInfo *slot, const CK_ATTRIBUTE *pTemplate, |
michael@0 | 1543 | int count, PRBool token) |
michael@0 | 1544 | { |
michael@0 | 1545 | CK_OBJECT_HANDLE objectID; |
michael@0 | 1546 | PK11GenericObject *obj; |
michael@0 | 1547 | CK_RV crv; |
michael@0 | 1548 | |
michael@0 | 1549 | PK11_EnterSlotMonitor(slot); |
michael@0 | 1550 | crv = PK11_CreateNewObject(slot, slot->session, pTemplate, count, |
michael@0 | 1551 | token, &objectID); |
michael@0 | 1552 | PK11_ExitSlotMonitor(slot); |
michael@0 | 1553 | if (crv != CKR_OK) { |
michael@0 | 1554 | PORT_SetError(PK11_MapError(crv)); |
michael@0 | 1555 | return NULL; |
michael@0 | 1556 | } |
michael@0 | 1557 | |
michael@0 | 1558 | obj = PORT_New(PK11GenericObject); |
michael@0 | 1559 | if ( !obj ) { |
michael@0 | 1560 | /* error set by PORT_New */ |
michael@0 | 1561 | return NULL; |
michael@0 | 1562 | } |
michael@0 | 1563 | |
michael@0 | 1564 | /* initialize it */ |
michael@0 | 1565 | obj->slot = PK11_ReferenceSlot(slot); |
michael@0 | 1566 | obj->objectID = objectID; |
michael@0 | 1567 | obj->next = NULL; |
michael@0 | 1568 | obj->prev = NULL; |
michael@0 | 1569 | return obj; |
michael@0 | 1570 | } |
michael@0 | 1571 | |
michael@0 | 1572 | /* |
michael@0 | 1573 | * Change an attribute on a raw object |
michael@0 | 1574 | */ |
michael@0 | 1575 | SECStatus |
michael@0 | 1576 | PK11_WriteRawAttribute(PK11ObjectType objType, void *objSpec, |
michael@0 | 1577 | CK_ATTRIBUTE_TYPE attrType, SECItem *item) |
michael@0 | 1578 | { |
michael@0 | 1579 | PK11SlotInfo *slot = NULL; |
michael@0 | 1580 | CK_OBJECT_HANDLE handle; |
michael@0 | 1581 | CK_ATTRIBUTE setTemplate; |
michael@0 | 1582 | CK_RV crv; |
michael@0 | 1583 | CK_SESSION_HANDLE rwsession; |
michael@0 | 1584 | |
michael@0 | 1585 | switch (objType) { |
michael@0 | 1586 | case PK11_TypeGeneric: |
michael@0 | 1587 | slot = ((PK11GenericObject *)objSpec)->slot; |
michael@0 | 1588 | handle = ((PK11GenericObject *)objSpec)->objectID; |
michael@0 | 1589 | break; |
michael@0 | 1590 | case PK11_TypePrivKey: |
michael@0 | 1591 | slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot; |
michael@0 | 1592 | handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID; |
michael@0 | 1593 | break; |
michael@0 | 1594 | case PK11_TypePubKey: |
michael@0 | 1595 | slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot; |
michael@0 | 1596 | handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID; |
michael@0 | 1597 | break; |
michael@0 | 1598 | case PK11_TypeSymKey: |
michael@0 | 1599 | slot = ((PK11SymKey *)objSpec)->slot; |
michael@0 | 1600 | handle = ((PK11SymKey *)objSpec)->objectID; |
michael@0 | 1601 | break; |
michael@0 | 1602 | case PK11_TypeCert: /* don't handle cert case for now */ |
michael@0 | 1603 | default: |
michael@0 | 1604 | break; |
michael@0 | 1605 | } |
michael@0 | 1606 | if (slot == NULL) { |
michael@0 | 1607 | PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); |
michael@0 | 1608 | return SECFailure; |
michael@0 | 1609 | } |
michael@0 | 1610 | |
michael@0 | 1611 | PK11_SETATTRS(&setTemplate, attrType, (CK_CHAR *) item->data, item->len); |
michael@0 | 1612 | rwsession = PK11_GetRWSession(slot); |
michael@0 | 1613 | if (rwsession == CK_INVALID_SESSION) { |
michael@0 | 1614 | PORT_SetError(SEC_ERROR_BAD_DATA); |
michael@0 | 1615 | return SECFailure; |
michael@0 | 1616 | } |
michael@0 | 1617 | crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, handle, |
michael@0 | 1618 | &setTemplate, 1); |
michael@0 | 1619 | PK11_RestoreROSession(slot, rwsession); |
michael@0 | 1620 | if (crv != CKR_OK) { |
michael@0 | 1621 | PORT_SetError(PK11_MapError(crv)); |
michael@0 | 1622 | return SECFailure; |
michael@0 | 1623 | } |
michael@0 | 1624 | return SECSuccess; |
michael@0 | 1625 | } |
michael@0 | 1626 | |
michael@0 | 1627 | |
michael@0 | 1628 | SECStatus |
michael@0 | 1629 | PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec, |
michael@0 | 1630 | CK_ATTRIBUTE_TYPE attrType, SECItem *item) |
michael@0 | 1631 | { |
michael@0 | 1632 | PK11SlotInfo *slot = NULL; |
michael@0 | 1633 | CK_OBJECT_HANDLE handle; |
michael@0 | 1634 | |
michael@0 | 1635 | switch (objType) { |
michael@0 | 1636 | case PK11_TypeGeneric: |
michael@0 | 1637 | slot = ((PK11GenericObject *)objSpec)->slot; |
michael@0 | 1638 | handle = ((PK11GenericObject *)objSpec)->objectID; |
michael@0 | 1639 | break; |
michael@0 | 1640 | case PK11_TypePrivKey: |
michael@0 | 1641 | slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot; |
michael@0 | 1642 | handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID; |
michael@0 | 1643 | break; |
michael@0 | 1644 | case PK11_TypePubKey: |
michael@0 | 1645 | slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot; |
michael@0 | 1646 | handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID; |
michael@0 | 1647 | break; |
michael@0 | 1648 | case PK11_TypeSymKey: |
michael@0 | 1649 | slot = ((PK11SymKey *)objSpec)->slot; |
michael@0 | 1650 | handle = ((PK11SymKey *)objSpec)->objectID; |
michael@0 | 1651 | break; |
michael@0 | 1652 | case PK11_TypeCert: /* don't handle cert case for now */ |
michael@0 | 1653 | default: |
michael@0 | 1654 | break; |
michael@0 | 1655 | } |
michael@0 | 1656 | if (slot == NULL) { |
michael@0 | 1657 | PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); |
michael@0 | 1658 | return SECFailure; |
michael@0 | 1659 | } |
michael@0 | 1660 | |
michael@0 | 1661 | return PK11_ReadAttribute(slot, handle, attrType, NULL, item); |
michael@0 | 1662 | } |
michael@0 | 1663 | |
michael@0 | 1664 | |
michael@0 | 1665 | /* |
michael@0 | 1666 | * return the object handle that matches the template |
michael@0 | 1667 | */ |
michael@0 | 1668 | CK_OBJECT_HANDLE |
michael@0 | 1669 | pk11_FindObjectByTemplate(PK11SlotInfo *slot,CK_ATTRIBUTE *theTemplate,int tsize) |
michael@0 | 1670 | { |
michael@0 | 1671 | CK_OBJECT_HANDLE object; |
michael@0 | 1672 | CK_RV crv = CKR_SESSION_HANDLE_INVALID; |
michael@0 | 1673 | CK_ULONG objectCount; |
michael@0 | 1674 | |
michael@0 | 1675 | /* |
michael@0 | 1676 | * issue the find |
michael@0 | 1677 | */ |
michael@0 | 1678 | PK11_EnterSlotMonitor(slot); |
michael@0 | 1679 | if (slot->session != CK_INVALID_SESSION) { |
michael@0 | 1680 | crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, |
michael@0 | 1681 | theTemplate, tsize); |
michael@0 | 1682 | } |
michael@0 | 1683 | if (crv != CKR_OK) { |
michael@0 | 1684 | PK11_ExitSlotMonitor(slot); |
michael@0 | 1685 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1686 | return CK_INVALID_HANDLE; |
michael@0 | 1687 | } |
michael@0 | 1688 | |
michael@0 | 1689 | crv=PK11_GETTAB(slot)->C_FindObjects(slot->session,&object,1,&objectCount); |
michael@0 | 1690 | PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); |
michael@0 | 1691 | PK11_ExitSlotMonitor(slot); |
michael@0 | 1692 | if ((crv != CKR_OK) || (objectCount < 1)) { |
michael@0 | 1693 | /* shouldn't use SSL_ERROR... here */ |
michael@0 | 1694 | PORT_SetError( crv != CKR_OK ? PK11_MapError(crv) : |
michael@0 | 1695 | SSL_ERROR_NO_CERTIFICATE); |
michael@0 | 1696 | return CK_INVALID_HANDLE; |
michael@0 | 1697 | } |
michael@0 | 1698 | |
michael@0 | 1699 | /* blow up if the PKCS #11 module returns us and invalid object handle */ |
michael@0 | 1700 | PORT_Assert(object != CK_INVALID_HANDLE); |
michael@0 | 1701 | return object; |
michael@0 | 1702 | } |
michael@0 | 1703 | |
michael@0 | 1704 | /* |
michael@0 | 1705 | * return all the object handles that matches the template |
michael@0 | 1706 | */ |
michael@0 | 1707 | CK_OBJECT_HANDLE * |
michael@0 | 1708 | pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, |
michael@0 | 1709 | int templCount, int *object_count) |
michael@0 | 1710 | { |
michael@0 | 1711 | CK_OBJECT_HANDLE *objID = NULL; |
michael@0 | 1712 | CK_ULONG returned_count = 0; |
michael@0 | 1713 | CK_RV crv = CKR_SESSION_HANDLE_INVALID; |
michael@0 | 1714 | |
michael@0 | 1715 | PK11_EnterSlotMonitor(slot); |
michael@0 | 1716 | if (slot->session != CK_INVALID_SESSION) { |
michael@0 | 1717 | crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, |
michael@0 | 1718 | findTemplate, templCount); |
michael@0 | 1719 | } |
michael@0 | 1720 | if (crv != CKR_OK) { |
michael@0 | 1721 | PK11_ExitSlotMonitor(slot); |
michael@0 | 1722 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1723 | *object_count = -1; |
michael@0 | 1724 | return NULL; |
michael@0 | 1725 | } |
michael@0 | 1726 | |
michael@0 | 1727 | |
michael@0 | 1728 | /* |
michael@0 | 1729 | * collect all the Matching Objects |
michael@0 | 1730 | */ |
michael@0 | 1731 | do { |
michael@0 | 1732 | CK_OBJECT_HANDLE *oldObjID = objID; |
michael@0 | 1733 | |
michael@0 | 1734 | if (objID == NULL) { |
michael@0 | 1735 | objID = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE)* |
michael@0 | 1736 | (*object_count+ PK11_SEARCH_CHUNKSIZE)); |
michael@0 | 1737 | } else { |
michael@0 | 1738 | objID = (CK_OBJECT_HANDLE *) PORT_Realloc(objID, |
michael@0 | 1739 | sizeof(CK_OBJECT_HANDLE)*(*object_count+PK11_SEARCH_CHUNKSIZE)); |
michael@0 | 1740 | } |
michael@0 | 1741 | |
michael@0 | 1742 | if (objID == NULL) { |
michael@0 | 1743 | if (oldObjID) PORT_Free(oldObjID); |
michael@0 | 1744 | break; |
michael@0 | 1745 | } |
michael@0 | 1746 | crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, |
michael@0 | 1747 | &objID[*object_count],PK11_SEARCH_CHUNKSIZE,&returned_count); |
michael@0 | 1748 | if (crv != CKR_OK) { |
michael@0 | 1749 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1750 | PORT_Free(objID); |
michael@0 | 1751 | objID = NULL; |
michael@0 | 1752 | break; |
michael@0 | 1753 | } |
michael@0 | 1754 | *object_count += returned_count; |
michael@0 | 1755 | } while (returned_count == PK11_SEARCH_CHUNKSIZE); |
michael@0 | 1756 | |
michael@0 | 1757 | PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); |
michael@0 | 1758 | PK11_ExitSlotMonitor(slot); |
michael@0 | 1759 | |
michael@0 | 1760 | if (objID && (*object_count == 0)) { |
michael@0 | 1761 | PORT_Free(objID); |
michael@0 | 1762 | return NULL; |
michael@0 | 1763 | } |
michael@0 | 1764 | if (objID == NULL) *object_count = -1; |
michael@0 | 1765 | return objID; |
michael@0 | 1766 | } |
michael@0 | 1767 | /* |
michael@0 | 1768 | * given a PKCS #11 object, match it's peer based on the KeyID. searchID |
michael@0 | 1769 | * is typically a privateKey or a certificate while the peer is the opposite |
michael@0 | 1770 | */ |
michael@0 | 1771 | CK_OBJECT_HANDLE |
michael@0 | 1772 | PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID, |
michael@0 | 1773 | CK_OBJECT_CLASS matchclass) |
michael@0 | 1774 | { |
michael@0 | 1775 | CK_ATTRIBUTE theTemplate[] = { |
michael@0 | 1776 | { CKA_ID, NULL, 0 }, |
michael@0 | 1777 | { CKA_CLASS, NULL, 0 } |
michael@0 | 1778 | }; |
michael@0 | 1779 | /* if you change the array, change the variable below as well */ |
michael@0 | 1780 | CK_ATTRIBUTE *keyclass = &theTemplate[1]; |
michael@0 | 1781 | int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); |
michael@0 | 1782 | /* if you change the array, change the variable below as well */ |
michael@0 | 1783 | CK_OBJECT_HANDLE peerID; |
michael@0 | 1784 | CK_OBJECT_HANDLE parent; |
michael@0 | 1785 | PLArenaPool *arena; |
michael@0 | 1786 | CK_RV crv; |
michael@0 | 1787 | |
michael@0 | 1788 | /* now we need to create space for the public key */ |
michael@0 | 1789 | arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); |
michael@0 | 1790 | if (arena == NULL) return CK_INVALID_HANDLE; |
michael@0 | 1791 | |
michael@0 | 1792 | crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize); |
michael@0 | 1793 | if (crv != CKR_OK) { |
michael@0 | 1794 | PORT_FreeArena(arena,PR_FALSE); |
michael@0 | 1795 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1796 | return CK_INVALID_HANDLE; |
michael@0 | 1797 | } |
michael@0 | 1798 | |
michael@0 | 1799 | if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) { |
michael@0 | 1800 | PORT_FreeArena(arena,PR_FALSE); |
michael@0 | 1801 | if (matchclass == CKO_CERTIFICATE) |
michael@0 | 1802 | PORT_SetError(SEC_ERROR_BAD_KEY); |
michael@0 | 1803 | else |
michael@0 | 1804 | PORT_SetError(SEC_ERROR_NO_KEY); |
michael@0 | 1805 | return CK_INVALID_HANDLE; |
michael@0 | 1806 | } |
michael@0 | 1807 | |
michael@0 | 1808 | |
michael@0 | 1809 | |
michael@0 | 1810 | /* |
michael@0 | 1811 | * issue the find |
michael@0 | 1812 | */ |
michael@0 | 1813 | parent = *(CK_OBJECT_CLASS *)(keyclass->pValue); |
michael@0 | 1814 | *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass; |
michael@0 | 1815 | |
michael@0 | 1816 | peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize); |
michael@0 | 1817 | PORT_FreeArena(arena,PR_FALSE); |
michael@0 | 1818 | |
michael@0 | 1819 | return peerID; |
michael@0 | 1820 | } |
michael@0 | 1821 | |
michael@0 | 1822 | /* |
michael@0 | 1823 | * count the number of objects that match the template. |
michael@0 | 1824 | */ |
michael@0 | 1825 | int |
michael@0 | 1826 | PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, |
michael@0 | 1827 | int templCount) |
michael@0 | 1828 | { |
michael@0 | 1829 | CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE]; |
michael@0 | 1830 | int object_count = 0; |
michael@0 | 1831 | CK_ULONG returned_count = 0; |
michael@0 | 1832 | CK_RV crv = CKR_SESSION_HANDLE_INVALID; |
michael@0 | 1833 | |
michael@0 | 1834 | PK11_EnterSlotMonitor(slot); |
michael@0 | 1835 | if (slot->session != CK_INVALID_SESSION) { |
michael@0 | 1836 | crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, |
michael@0 | 1837 | findTemplate, templCount); |
michael@0 | 1838 | } |
michael@0 | 1839 | if (crv != CKR_OK) { |
michael@0 | 1840 | PK11_ExitSlotMonitor(slot); |
michael@0 | 1841 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1842 | return object_count; |
michael@0 | 1843 | } |
michael@0 | 1844 | |
michael@0 | 1845 | /* |
michael@0 | 1846 | * collect all the Matching Objects |
michael@0 | 1847 | */ |
michael@0 | 1848 | do { |
michael@0 | 1849 | crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, objID, |
michael@0 | 1850 | PK11_SEARCH_CHUNKSIZE, |
michael@0 | 1851 | &returned_count); |
michael@0 | 1852 | if (crv != CKR_OK) { |
michael@0 | 1853 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 1854 | break; |
michael@0 | 1855 | } |
michael@0 | 1856 | object_count += returned_count; |
michael@0 | 1857 | } while (returned_count == PK11_SEARCH_CHUNKSIZE); |
michael@0 | 1858 | |
michael@0 | 1859 | PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); |
michael@0 | 1860 | PK11_ExitSlotMonitor(slot); |
michael@0 | 1861 | return object_count; |
michael@0 | 1862 | } |
michael@0 | 1863 | |
michael@0 | 1864 | /* |
michael@0 | 1865 | * Traverse all the objects in a given slot. |
michael@0 | 1866 | */ |
michael@0 | 1867 | SECStatus |
michael@0 | 1868 | PK11_TraverseSlot(PK11SlotInfo *slot, void *arg) |
michael@0 | 1869 | { |
michael@0 | 1870 | int i; |
michael@0 | 1871 | CK_OBJECT_HANDLE *objID = NULL; |
michael@0 | 1872 | int object_count = 0; |
michael@0 | 1873 | pk11TraverseSlot *slotcb = (pk11TraverseSlot*) arg; |
michael@0 | 1874 | |
michael@0 | 1875 | objID = pk11_FindObjectsByTemplate(slot,slotcb->findTemplate, |
michael@0 | 1876 | slotcb->templateCount,&object_count); |
michael@0 | 1877 | |
michael@0 | 1878 | /*Actually this isn't a failure... there just were no objs to be found*/ |
michael@0 | 1879 | if (object_count == 0) { |
michael@0 | 1880 | return SECSuccess; |
michael@0 | 1881 | } |
michael@0 | 1882 | |
michael@0 | 1883 | if (objID == NULL) { |
michael@0 | 1884 | return SECFailure; |
michael@0 | 1885 | } |
michael@0 | 1886 | |
michael@0 | 1887 | for (i=0; i < object_count; i++) { |
michael@0 | 1888 | (*slotcb->callback)(slot,objID[i],slotcb->callbackArg); |
michael@0 | 1889 | } |
michael@0 | 1890 | PORT_Free(objID); |
michael@0 | 1891 | return SECSuccess; |
michael@0 | 1892 | } |
michael@0 | 1893 | |
michael@0 | 1894 | /* |
michael@0 | 1895 | * Traverse all the objects in all slots. |
michael@0 | 1896 | */ |
michael@0 | 1897 | SECStatus |
michael@0 | 1898 | pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *), |
michael@0 | 1899 | void *arg, PRBool forceLogin, void *wincx) { |
michael@0 | 1900 | PK11SlotList *list; |
michael@0 | 1901 | PK11SlotListElement *le; |
michael@0 | 1902 | SECStatus rv; |
michael@0 | 1903 | |
michael@0 | 1904 | /* get them all! */ |
michael@0 | 1905 | list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,wincx); |
michael@0 | 1906 | if (list == NULL) return SECFailure; |
michael@0 | 1907 | |
michael@0 | 1908 | /* look at each slot and authenticate as necessary */ |
michael@0 | 1909 | for (le = list->head ; le; le = le->next) { |
michael@0 | 1910 | if (forceLogin) { |
michael@0 | 1911 | rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx); |
michael@0 | 1912 | if (rv != SECSuccess) { |
michael@0 | 1913 | continue; |
michael@0 | 1914 | } |
michael@0 | 1915 | } |
michael@0 | 1916 | if (callback) { |
michael@0 | 1917 | (*callback)(le->slot,arg); |
michael@0 | 1918 | } |
michael@0 | 1919 | } |
michael@0 | 1920 | |
michael@0 | 1921 | PK11_FreeSlotList(list); |
michael@0 | 1922 | |
michael@0 | 1923 | return SECSuccess; |
michael@0 | 1924 | } |
michael@0 | 1925 | |
michael@0 | 1926 | CK_OBJECT_HANDLE * |
michael@0 | 1927 | PK11_FindObjectsFromNickname(char *nickname,PK11SlotInfo **slotptr, |
michael@0 | 1928 | CK_OBJECT_CLASS objclass, int *returnCount, void *wincx) |
michael@0 | 1929 | { |
michael@0 | 1930 | char *tokenName; |
michael@0 | 1931 | char *delimit; |
michael@0 | 1932 | PK11SlotInfo *slot; |
michael@0 | 1933 | CK_OBJECT_HANDLE *objID; |
michael@0 | 1934 | CK_ATTRIBUTE findTemplate[] = { |
michael@0 | 1935 | { CKA_LABEL, NULL, 0}, |
michael@0 | 1936 | { CKA_CLASS, NULL, 0}, |
michael@0 | 1937 | }; |
michael@0 | 1938 | int findCount = sizeof(findTemplate)/sizeof(findTemplate[0]); |
michael@0 | 1939 | SECStatus rv; |
michael@0 | 1940 | PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass)); |
michael@0 | 1941 | |
michael@0 | 1942 | *slotptr = slot = NULL; |
michael@0 | 1943 | *returnCount = 0; |
michael@0 | 1944 | /* first find the slot associated with this nickname */ |
michael@0 | 1945 | if ((delimit = PORT_Strchr(nickname,':')) != NULL) { |
michael@0 | 1946 | int len = delimit - nickname; |
michael@0 | 1947 | tokenName = (char*)PORT_Alloc(len+1); |
michael@0 | 1948 | PORT_Memcpy(tokenName,nickname,len); |
michael@0 | 1949 | tokenName[len] = 0; |
michael@0 | 1950 | |
michael@0 | 1951 | slot = *slotptr = PK11_FindSlotByName(tokenName); |
michael@0 | 1952 | PORT_Free(tokenName); |
michael@0 | 1953 | /* if we couldn't find a slot, assume the nickname is an internal cert |
michael@0 | 1954 | * with no proceding slot name */ |
michael@0 | 1955 | if (slot == NULL) { |
michael@0 | 1956 | slot = *slotptr = PK11_GetInternalKeySlot(); |
michael@0 | 1957 | } else { |
michael@0 | 1958 | nickname = delimit+1; |
michael@0 | 1959 | } |
michael@0 | 1960 | } else { |
michael@0 | 1961 | *slotptr = slot = PK11_GetInternalKeySlot(); |
michael@0 | 1962 | } |
michael@0 | 1963 | if (slot == NULL) { |
michael@0 | 1964 | return CK_INVALID_HANDLE; |
michael@0 | 1965 | } |
michael@0 | 1966 | |
michael@0 | 1967 | rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); |
michael@0 | 1968 | if (rv != SECSuccess) { |
michael@0 | 1969 | PK11_FreeSlot(slot); |
michael@0 | 1970 | *slotptr = NULL; |
michael@0 | 1971 | return CK_INVALID_HANDLE; |
michael@0 | 1972 | } |
michael@0 | 1973 | |
michael@0 | 1974 | findTemplate[0].pValue = nickname; |
michael@0 | 1975 | findTemplate[0].ulValueLen = PORT_Strlen(nickname); |
michael@0 | 1976 | objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,returnCount); |
michael@0 | 1977 | if (objID == NULL) { |
michael@0 | 1978 | /* PKCS #11 isn't clear on whether or not the NULL is |
michael@0 | 1979 | * stored in the template.... try the find again with the |
michael@0 | 1980 | * full null terminated string. */ |
michael@0 | 1981 | findTemplate[0].ulValueLen += 1; |
michael@0 | 1982 | objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount, |
michael@0 | 1983 | returnCount); |
michael@0 | 1984 | if (objID == NULL) { |
michael@0 | 1985 | /* Well that's the best we can do. It's just not here */ |
michael@0 | 1986 | /* what about faked nicknames? */ |
michael@0 | 1987 | PK11_FreeSlot(slot); |
michael@0 | 1988 | *slotptr = NULL; |
michael@0 | 1989 | *returnCount = 0; |
michael@0 | 1990 | } |
michael@0 | 1991 | } |
michael@0 | 1992 | |
michael@0 | 1993 | return objID; |
michael@0 | 1994 | } |
michael@0 | 1995 | |
michael@0 | 1996 | SECItem * |
michael@0 | 1997 | pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) |
michael@0 | 1998 | { |
michael@0 | 1999 | CK_ATTRIBUTE theTemplate[] = { |
michael@0 | 2000 | { CKA_ID, NULL, 0 }, |
michael@0 | 2001 | }; |
michael@0 | 2002 | int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); |
michael@0 | 2003 | CK_RV crv; |
michael@0 | 2004 | SECItem *item; |
michael@0 | 2005 | |
michael@0 | 2006 | item = SECITEM_AllocItem(NULL, NULL, 0); |
michael@0 | 2007 | |
michael@0 | 2008 | if (item == NULL) { |
michael@0 | 2009 | return NULL; |
michael@0 | 2010 | } |
michael@0 | 2011 | |
michael@0 | 2012 | crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize); |
michael@0 | 2013 | if (crv != CKR_OK) { |
michael@0 | 2014 | SECITEM_FreeItem(item,PR_TRUE); |
michael@0 | 2015 | PORT_SetError( PK11_MapError(crv) ); |
michael@0 | 2016 | return NULL; |
michael@0 | 2017 | } |
michael@0 | 2018 | |
michael@0 | 2019 | item->data = (unsigned char*) theTemplate[0].pValue; |
michael@0 | 2020 | item->len =theTemplate[0].ulValueLen; |
michael@0 | 2021 | |
michael@0 | 2022 | return item; |
michael@0 | 2023 | } |
michael@0 | 2024 |