forked from frankosterfeld/qtkeychain
-
Notifications
You must be signed in to change notification settings - Fork 0
/
keychain_apple.mm
146 lines (124 loc) · 6.37 KB
/
keychain_apple.mm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/******************************************************************************
* Copyright (C) 2016 Mathias Hasselmann <[email protected]> *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
#include "keychain_p.h"
#import <Foundation/Foundation.h>
#import <Security/Security.h>
using namespace QKeychain;
struct ErrorDescription
{
QKeychain::Error code;
QString message;
ErrorDescription(QKeychain::Error code, const QString &message)
: code(code), message(message) {}
static ErrorDescription fromStatus(OSStatus status)
{
switch(status) {
case errSecSuccess:
return ErrorDescription(QKeychain::NoError, Job::tr("No error"));
case errSecItemNotFound:
return ErrorDescription(QKeychain::EntryNotFound, Job::tr("The specified item could not be found in the keychain"));
case errSecUserCanceled:
return ErrorDescription(QKeychain::AccessDeniedByUser, Job::tr("User canceled the operation"));
case errSecInteractionNotAllowed:
return ErrorDescription(QKeychain::AccessDenied, Job::tr("User interaction is not allowed"));
case errSecNotAvailable:
return ErrorDescription(QKeychain::AccessDenied, Job::tr("No keychain is available. You may need to restart your computer"));
case errSecAuthFailed:
return ErrorDescription(QKeychain::AccessDenied, Job::tr("The user name or passphrase you entered is not correct"));
case errSecVerifyFailed:
return ErrorDescription(QKeychain::AccessDenied, Job::tr("A cryptographic verification failure has occurred"));
case errSecUnimplemented:
return ErrorDescription(QKeychain::NotImplemented, Job::tr("Function or operation not implemented"));
case errSecIO:
return ErrorDescription(QKeychain::OtherError, Job::tr("I/O error"));
case errSecOpWr:
return ErrorDescription(QKeychain::OtherError, Job::tr("Already open with with write permission"));
case errSecParam:
return ErrorDescription(QKeychain::OtherError, Job::tr("Invalid parameters passed to a function"));
case errSecAllocate:
return ErrorDescription(QKeychain::OtherError, Job::tr("Failed to allocate memory"));
case errSecBadReq:
return ErrorDescription(QKeychain::OtherError, Job::tr("Bad parameter or invalid state for operation"));
case errSecInternalComponent:
return ErrorDescription(QKeychain::OtherError, Job::tr("An internal component failed"));
case errSecDuplicateItem:
return ErrorDescription(QKeychain::OtherError, Job::tr("The specified item already exists in the keychain"));
case errSecDecode:
return ErrorDescription(QKeychain::OtherError, Job::tr("Unable to decode the provided data"));
}
return ErrorDescription(QKeychain::OtherError, Job::tr("Unknown error"));
}
};
void ReadPasswordJobPrivate::scheduledStart()
{
NSDictionary *const query = @{
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
(__bridge id) kSecReturnData: @YES,
};
CFTypeRef dataRef = nil;
const OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &dataRef);
data.clear();
mode = Binary;
if (status == errSecSuccess) {
if (dataRef)
data = QByteArray::fromCFData((CFDataRef) dataRef);
q->emitFinished();
} else {
const ErrorDescription error = ErrorDescription::fromStatus(status);
q->emitFinishedWithError(error.code, Job::tr("Could not retrieve private key from keystore: %1").arg(error.message));
}
if (dataRef)
CFRelease(dataRef);
}
void WritePasswordJobPrivate::scheduledStart()
{
NSDictionary *const query = @{
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
};
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, nil);
if (status == errSecSuccess) {
NSDictionary *const update = @{
(__bridge id) kSecValueData: (__bridge NSData *) data.toCFData(),
};
status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef) update);
} else {
NSDictionary *const insert = @{
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
(__bridge id) kSecValueData: (__bridge NSData *) data.toCFData(),
};
status = SecItemAdd((__bridge CFDictionaryRef) insert, nil);
}
if (status == errSecSuccess) {
q->emitFinished();
} else {
const ErrorDescription error = ErrorDescription::fromStatus(status);
q->emitFinishedWithError(error.code, tr("Could not store data in settings: %1").arg(error.message));
}
}
void DeletePasswordJobPrivate::scheduledStart()
{
const NSDictionary *const query = @{
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
};
const OSStatus status = SecItemDelete((__bridge CFDictionaryRef) query);
if (status == errSecSuccess) {
q->emitFinished();
} else {
const ErrorDescription error = ErrorDescription::fromStatus(status);
q->emitFinishedWithError(error.code, Job::tr("Could not remove private key from keystore: %1").arg(error.message));
}
}