Imported Upstream version 5.0.0.61
Former-commit-id: 8969ac411e933f8c8203fa18878df70bb80cfba4
This commit is contained in:
parent
5005e1465f
commit
270395db27
@ -36,14 +36,63 @@ namespace Mono.AppleTls
|
||||
*/
|
||||
var certificate2 = certificate as X509Certificate2;
|
||||
if (certificate2 != null)
|
||||
#if MONOTOUCH
|
||||
return SecIdentity.Import (certificate2);
|
||||
#else
|
||||
return SecImportExport.ItemImport (certificate2);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Otherwise, we require the private key to be in the keychain.
|
||||
* Reading Certificates from the Mac Keychain
|
||||
* ==========================================
|
||||
*
|
||||
* Reading the private key from the keychain is a new feature introduced with
|
||||
* AppleTls on XamMac and iOS. On Desktop Mono, this new feature has several
|
||||
* known issues and it also did not received any testing yet. We go back to the old
|
||||
* way of doing things, which is to explicitly provide an X509Certificate2 with a
|
||||
* private key.
|
||||
*
|
||||
* Keychain Dialog Popups
|
||||
* ======================
|
||||
*
|
||||
* When using Xamarin.Mac or Xamarin.iOS, we try to search the keychain
|
||||
* for the certificate and private key.
|
||||
*
|
||||
* On Xamarin.iOS, this is easy because each app has its own keychain.
|
||||
*
|
||||
* On Xamarin.Mac, the .app package needs to be trusted via code-sign
|
||||
* to get permission to access the user's keychain. [FIXME: I still have to
|
||||
* research how to actually do that.] Without this, you will get a popup
|
||||
* message each time, asking you whether you want to allow the app to access
|
||||
* the keychain, but you can make these go away by selecting "Trust always".
|
||||
*
|
||||
* On Desktop Mono, this is problematic because selecting "Trust always"
|
||||
* give the 'mono' binary (and thus everything you'll ever run with Mono)
|
||||
* permission to retrieve the private key from the keychain.
|
||||
*
|
||||
* This code would also trigger constant keychain popup messages,
|
||||
* which could only be suppressed by granting full trust. It also makes it
|
||||
* impossible to run Mono in headless mode.
|
||||
*
|
||||
* SecIdentityCreate
|
||||
* =================
|
||||
*
|
||||
* To avoid these problems, we are currently using an undocumented API
|
||||
* called SecIdentityRef() to avoid using the Mac keychain whenever a
|
||||
* X509Certificate2 with a private key is used.
|
||||
*
|
||||
* On iOS and XamMac, you can still provide the X509Certificate without
|
||||
* a private key - in this case, a keychain search will be performed (and you
|
||||
* may get a popup message on XamMac).
|
||||
*/
|
||||
|
||||
#if MOBILE
|
||||
using (var secCert = new SecCertificate (certificate)) {
|
||||
return SecKeyChain.FindIdentity (secCert, true);
|
||||
}
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static SecIdentity GetIdentity (X509Certificate certificate, out SecCertificate[] intermediateCerts)
|
||||
|
@ -31,6 +31,7 @@
|
||||
#if SECURITY_DEP && MONO_FEATURE_APPLETLS
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Mono.Net;
|
||||
@ -198,6 +199,8 @@ namespace Mono.AppleTls {
|
||||
|
||||
static readonly CFString ImportExportPassphase;
|
||||
static readonly CFString ImportItemIdentity;
|
||||
static readonly CFString ImportExportAccess;
|
||||
static readonly CFString ImportExportKeychain;
|
||||
|
||||
static SecIdentity ()
|
||||
{
|
||||
@ -208,6 +211,8 @@ namespace Mono.AppleTls {
|
||||
try {
|
||||
ImportExportPassphase = CFObject.GetStringConstant (handle, "kSecImportExportPassphrase");
|
||||
ImportItemIdentity = CFObject.GetStringConstant (handle, "kSecImportItemIdentity");
|
||||
ImportExportAccess = CFObject.GetStringConstant (handle, "kSecImportExportAccess");
|
||||
ImportExportKeychain = CFObject.GetStringConstant (handle, "kSecImportExportKeychain");
|
||||
} finally {
|
||||
CFObject.dlclose (handle);
|
||||
}
|
||||
@ -240,16 +245,46 @@ namespace Mono.AppleTls {
|
||||
}
|
||||
}
|
||||
|
||||
public static SecIdentity Import (byte[] data, string password)
|
||||
internal class ImportOptions
|
||||
{
|
||||
#if !MONOTOUCH
|
||||
public SecAccess Access {
|
||||
get; set;
|
||||
}
|
||||
public SecKeyChain KeyChain {
|
||||
get; set;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static CFDictionary CreateImportOptions (CFString password, ImportOptions options = null)
|
||||
{
|
||||
if (options == null)
|
||||
return CFDictionary.FromObjectAndKey (password.Handle, ImportExportPassphase.Handle);
|
||||
|
||||
var items = new List<Tuple<IntPtr, IntPtr>> ();
|
||||
items.Add (new Tuple<IntPtr, IntPtr> (ImportExportPassphase.Handle, password.Handle));
|
||||
|
||||
#if !MONOTOUCH
|
||||
if (options.KeyChain != null)
|
||||
items.Add (new Tuple<IntPtr, IntPtr> (ImportExportKeychain.Handle, options.KeyChain.Handle));
|
||||
if (options.Access != null)
|
||||
items.Add (new Tuple<IntPtr, IntPtr> (ImportExportAccess.Handle, options.Access.Handle));
|
||||
#endif
|
||||
|
||||
return CFDictionary.FromKeysAndObjects (items);
|
||||
}
|
||||
|
||||
public static SecIdentity Import (byte[] data, string password, ImportOptions options = null)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException ("data");
|
||||
if (string.IsNullOrEmpty (password)) // SecPKCS12Import() doesn't allow empty passwords.
|
||||
throw new ArgumentException ("password");
|
||||
using (var pwstring = CFString.Create (password))
|
||||
using (var options = CFDictionary.FromObjectAndKey (pwstring.Handle, ImportExportPassphase.Handle)) {
|
||||
using (var optionDict = CreateImportOptions (pwstring, options)) {
|
||||
CFDictionary [] array;
|
||||
SecStatusCode result = SecImportExport.ImportPkcs12 (data, options, out array);
|
||||
SecStatusCode result = SecImportExport.ImportPkcs12 (data, optionDict, out array);
|
||||
if (result != SecStatusCode.Success)
|
||||
throw new InvalidOperationException (result.ToString ());
|
||||
|
||||
@ -257,7 +292,7 @@ namespace Mono.AppleTls {
|
||||
}
|
||||
}
|
||||
|
||||
public static SecIdentity Import (X509Certificate2 certificate)
|
||||
public static SecIdentity Import (X509Certificate2 certificate, ImportOptions options = null)
|
||||
{
|
||||
if (certificate == null)
|
||||
throw new ArgumentNullException ("certificate");
|
||||
@ -270,7 +305,7 @@ namespace Mono.AppleTls {
|
||||
*/
|
||||
var password = Guid.NewGuid ().ToString ();
|
||||
var pkcs12 = certificate.Export (X509ContentType.Pfx, password);
|
||||
return Import (pkcs12, password);
|
||||
return Import (pkcs12, password, options);
|
||||
}
|
||||
|
||||
~SecIdentity ()
|
||||
@ -301,6 +336,7 @@ namespace Mono.AppleTls {
|
||||
|
||||
partial class SecKey : INativeObject, IDisposable {
|
||||
internal IntPtr handle;
|
||||
internal IntPtr owner;
|
||||
|
||||
public SecKey (IntPtr handle, bool owns = false)
|
||||
{
|
||||
@ -309,6 +345,17 @@ namespace Mono.AppleTls {
|
||||
CFObject.CFRetain (handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* SecItemImport() returns a SecArrayRef. We need to free the array, not the items inside it.
|
||||
*
|
||||
*/
|
||||
internal SecKey (IntPtr handle, IntPtr owner)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.owner = owner;
|
||||
CFObject.CFRetain (owner);
|
||||
}
|
||||
|
||||
[DllImport (AppleTlsContext.SecurityLibrary, EntryPoint="SecKeyGetTypeID")]
|
||||
public extern static IntPtr GetTypeID ();
|
||||
|
||||
@ -331,11 +378,73 @@ namespace Mono.AppleTls {
|
||||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (handle != IntPtr.Zero){
|
||||
if (owner != IntPtr.Zero) {
|
||||
CFObject.CFRelease (owner);
|
||||
owner = handle = IntPtr.Zero;
|
||||
} else if (handle != IntPtr.Zero) {
|
||||
CFObject.CFRelease (handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !MONOTOUCH
|
||||
class SecAccess : INativeObject, IDisposable {
|
||||
internal IntPtr handle;
|
||||
|
||||
public SecAccess (IntPtr handle, bool owns = false)
|
||||
{
|
||||
this.handle = handle;
|
||||
if (!owns)
|
||||
CFObject.CFRetain (handle);
|
||||
}
|
||||
|
||||
~SecAccess ()
|
||||
{
|
||||
Dispose (false);
|
||||
}
|
||||
|
||||
public IntPtr Handle {
|
||||
get {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport (AppleTlsContext.SecurityLibrary)]
|
||||
extern static /* OSStatus */ SecStatusCode SecAccessCreate (/* CFStringRef */ IntPtr descriptor, /* CFArrayRef */ IntPtr trustedList, /* SecAccessRef _Nullable * */ out IntPtr accessRef);
|
||||
|
||||
public static SecAccess Create (string descriptor)
|
||||
{
|
||||
var descriptorHandle = CFString.Create (descriptor);
|
||||
if (descriptorHandle == null)
|
||||
throw new InvalidOperationException ();
|
||||
|
||||
try {
|
||||
IntPtr accessRef;
|
||||
var result = SecAccessCreate (descriptorHandle.Handle, IntPtr.Zero, out accessRef);
|
||||
if (result != SecStatusCode.Success)
|
||||
throw new InvalidOperationException (result.ToString ());
|
||||
|
||||
return new SecAccess (accessRef, true);
|
||||
} finally {
|
||||
descriptorHandle.Dispose ();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (handle != IntPtr.Zero) {
|
||||
CFObject.CFRelease (handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -9,8 +9,386 @@ namespace Mono.AppleTls {
|
||||
// values are defined in Security.framework/Headers/SecBase.h
|
||||
enum SecStatusCode {
|
||||
Success = 0,
|
||||
DuplicateItem = -25299,
|
||||
Unimplemented = -4,
|
||||
DiskFull = -34,
|
||||
IO = -36,
|
||||
OpWr = -49,
|
||||
Param = -50,
|
||||
WritePermissions = -61,
|
||||
Allocate = -108,
|
||||
UserCanceled = -128,
|
||||
BadReq = -909,
|
||||
InternalComponent = -2070,
|
||||
CoreFoundationUnknown = -4960,
|
||||
NotAvailable = -25291,
|
||||
ReadOnly = -25292,
|
||||
AuthFailed = -25293,
|
||||
NoSuchKeyChain = -25294,
|
||||
InvalidKeyChain = -25295,
|
||||
DuplicateKeyChain = -25296,
|
||||
DuplicateItem = -25299,
|
||||
ItemNotFound = -25300,
|
||||
InteractionNotAllowed = -25308,
|
||||
Decode = -26275,
|
||||
DuplicateCallback = -25297,
|
||||
InvalidCallback = -25298,
|
||||
BufferTooSmall = -25301,
|
||||
DataTooLarge = -25302,
|
||||
NoSuchAttribute = -25303,
|
||||
InvalidItemRef = -25304,
|
||||
InvalidSearchRef = -25305,
|
||||
NoSuchClass = -25306,
|
||||
NoDefaultKeychain = -25307,
|
||||
ReadOnlyAttribute = -25309,
|
||||
WrongSecVersion = -25310,
|
||||
KeySizeNotAllowed = -25311,
|
||||
NoStorageModule = -25312,
|
||||
NoCertificateModule = -25313,
|
||||
NoPolicyModule = -25314,
|
||||
InteractionRequired = -25315,
|
||||
DataNotAvailable = -25316,
|
||||
DataNotModifiable = -25317,
|
||||
CreateChainFailed = -25318,
|
||||
InvalidPrefsDomain = -25319,
|
||||
InDarkWake = -25320,
|
||||
ACLNotSimple = -25240,
|
||||
PolicyNotFound = -25241,
|
||||
InvalidTrustSetting = -25242,
|
||||
NoAccessForItem = -25243,
|
||||
InvalidOwnerEdit = -25244,
|
||||
TrustNotAvailable = -25245,
|
||||
UnsupportedFormat = -25256,
|
||||
UnknownFormat = -25257,
|
||||
KeyIsSensitive = -25258,
|
||||
MultiplePrivateKeys = -25259,
|
||||
PassphraseRequired = -25260,
|
||||
InvalidPasswordRef = -25261,
|
||||
InvalidTrustSettings = -25262,
|
||||
NoTrustSettings = -25263,
|
||||
Pkcs12VerifyFailure = -25264,
|
||||
NotSigner = -26267,
|
||||
ServiceNotAvailable = -67585,
|
||||
InsufficientClientID = -67586,
|
||||
DeviceReset = -67587,
|
||||
DeviceFailed = -67588,
|
||||
AppleAddAppACLSubject = -67589,
|
||||
ApplePublicKeyIncomplete = -67590,
|
||||
AppleSignatureMismatch = -67591,
|
||||
AppleInvalidKeyStartDate = -67592,
|
||||
AppleInvalidKeyEndDate = -67593,
|
||||
ConversionError = -67594,
|
||||
AppleSSLv2Rollback = -67595,
|
||||
QuotaExceeded = -67596,
|
||||
FileTooBig = -67597,
|
||||
InvalidDatabaseBlob = -67598,
|
||||
InvalidKeyBlob = -67599,
|
||||
IncompatibleDatabaseBlob = -67600,
|
||||
IncompatibleKeyBlob = -67601,
|
||||
HostNameMismatch = -67602,
|
||||
UnknownCriticalExtensionFlag = -67603,
|
||||
NoBasicConstraints = -67604,
|
||||
NoBasicConstraintsCA = -67605,
|
||||
InvalidAuthorityKeyID = -67606,
|
||||
InvalidSubjectKeyID = -67607, /* The subject key ID is not valid. */
|
||||
InvalidKeyUsageForPolicy = -67608, /* The key usage is not valid for the specified policy. */
|
||||
InvalidExtendedKeyUsage = -67609, /* The extended key usage is not valid. */
|
||||
InvalidIDLinkage = -67610, /* The ID linkage is not valid. */
|
||||
PathLengthConstraintExceeded = -67611, /* The path length constraint was exceeded. */
|
||||
InvalidRoot = -67612, /* The root or anchor certificate is not valid. */
|
||||
CRLExpired = -67613, /* The CRL has expired. */
|
||||
CRLNotValidYet = -67614, /* The CRL is not yet valid. */
|
||||
CRLNotFound = -67615, /* The CRL was not found. */
|
||||
CRLServerDown = -67616, /* The CRL server is down. */
|
||||
CRLBadURI = -67617, /* The CRL has a bad Uniform Resource Identifier. */
|
||||
UnknownCertExtension = -67618, /* An unknown certificate extension was encountered. */
|
||||
UnknownCRLExtension = -67619, /* An unknown CRL extension was encountered. */
|
||||
CRLNotTrusted = -67620, /* The CRL is not trusted. */
|
||||
CRLPolicyFailed = -67621, /* The CRL policy failed. */
|
||||
IDPFailure = -67622, /* The issuing distribution point was not valid. */
|
||||
SMIMEEmailAddressesNotFound = -67623, /* An email address mismatch was encountered. */
|
||||
SMIMEBadExtendedKeyUsage = -67624, /* The appropriate extended key usage for SMIME was not found. */
|
||||
SMIMEBadKeyUsage = -67625, /* The key usage is not compatible with SMIME. */
|
||||
SMIMEKeyUsageNotCritical = -67626, /* The key usage extension is not marked as critical. */
|
||||
SMIMENoEmailAddress = -67627, /* No email address was found in the certificate. */
|
||||
SMIMESubjAltNameNotCritical = -67628, /* The subject alternative name extension is not marked as critical. */
|
||||
SSLBadExtendedKeyUsage = -67629, /* The appropriate extended key usage for SSL was not found. */
|
||||
OCSPBadResponse = -67630, /* The OCSP response was incorrect or could not be parsed. */
|
||||
OCSPBadRequest = -67631, /* The OCSP request was incorrect or could not be parsed. */
|
||||
OCSPUnavailable = -67632, /* OCSP service is unavailable. */
|
||||
OCSPStatusUnrecognized = -67633, /* The OCSP server did not recognize this certificate. */
|
||||
EndOfData = -67634, /* An end-of-data was detected. */
|
||||
IncompleteCertRevocationCheck = -67635, /* An incomplete certificate revocation check occurred. */
|
||||
NetworkFailure = -67636, /* A network failure occurred. */
|
||||
OCSPNotTrustedToAnchor = -67637, /* The OCSP response was not trusted to a root or anchor certificate. */
|
||||
RecordModified = -67638, /* The record was modified. */
|
||||
OCSPSignatureError = -67639, /* The OCSP response had an invalid signature. */
|
||||
OCSPNoSigner = -67640, /* The OCSP response had no signer. */
|
||||
OCSPResponderMalformedReq = -67641, /* The OCSP responder was given a malformed request. */
|
||||
OCSPResponderInternalError = -67642, /* The OCSP responder encountered an internal error. */
|
||||
OCSPResponderTryLater = -67643, /* The OCSP responder is busy, try again later. */
|
||||
OCSPResponderSignatureRequired = -67644, /* The OCSP responder requires a signature. */
|
||||
OCSPResponderUnauthorized = -67645, /* The OCSP responder rejected this request as unauthorized. */
|
||||
OCSPResponseNonceMismatch = -67646, /* The OCSP response nonce did not match the request. */
|
||||
CodeSigningBadCertChainLength = -67647, /* Code signing encountered an incorrect certificate chain length. */
|
||||
CodeSigningNoBasicConstraints = -67648, /* Code signing found no basic constraints. */
|
||||
CodeSigningBadPathLengthConstraint = -67649, /* Code signing encountered an incorrect path length constraint. */
|
||||
CodeSigningNoExtendedKeyUsage = -67650, /* Code signing found no extended key usage. */
|
||||
CodeSigningDevelopment = -67651, /* Code signing indicated use of a development-only certificate. */
|
||||
ResourceSignBadCertChainLength = -67652, /* Resource signing has encountered an incorrect certificate chain length. */
|
||||
ResourceSignBadExtKeyUsage = -67653, /* Resource signing has encountered an error in the extended key usage. */
|
||||
TrustSettingDeny = -67654, /* The trust setting for this policy was set to Deny. */
|
||||
InvalidSubjectName = -67655, /* An invalid certificate subject name was encountered. */
|
||||
UnknownQualifiedCertStatement = -67656, /* An unknown qualified certificate statement was encountered. */
|
||||
MobileMeRequestQueued = -67657, /* The MobileMe request will be sent during the next connection. */
|
||||
MobileMeRequestRedirected = -67658, /* The MobileMe request was redirected. */
|
||||
MobileMeServerError = -67659, /* A MobileMe server error occurred. */
|
||||
MobileMeServerNotAvailable = -67660, /* The MobileMe server is not available. */
|
||||
MobileMeServerAlreadyExists = -67661, /* The MobileMe server reported that the item already exists. */
|
||||
MobileMeServerServiceErr = -67662, /* A MobileMe service error has occurred. */
|
||||
MobileMeRequestAlreadyPending = -67663, /* A MobileMe request is already pending. */
|
||||
MobileMeNoRequestPending = -67664, /* MobileMe has no request pending. */
|
||||
MobileMeCSRVerifyFailure = -67665, /* A MobileMe CSR verification failure has occurred. */
|
||||
MobileMeFailedConsistencyCheck = -67666, /* MobileMe has found a failed consistency check. */
|
||||
NotInitialized = -67667, /* A function was called without initializing CSSM. */
|
||||
InvalidHandleUsage = -67668, /* The CSSM handle does not match with the service type. */
|
||||
PVCReferentNotFound = -67669, /* A reference to the calling module was not found in the list of authorized callers. */
|
||||
FunctionIntegrityFail = -67670, /* A function address was not within the verified module. */
|
||||
InternalError = -67671, /* An internal error has occurred. */
|
||||
MemoryError = -67672, /* A memory error has occurred. */
|
||||
InvalidData = -67673, /* Invalid data was encountered. */
|
||||
MDSError = -67674, /* A Module Directory Service error has occurred. */
|
||||
InvalidPointer = -67675, /* An invalid pointer was encountered. */
|
||||
SelfCheckFailed = -67676, /* Self-check has failed. */
|
||||
FunctionFailed = -67677, /* A function has failed. */
|
||||
ModuleManifestVerifyFailed = -67678, /* A module manifest verification failure has occurred. */
|
||||
InvalidGUID = -67679, /* An invalid GUID was encountered. */
|
||||
InvalidHandle = -67680, /* An invalid handle was encountered. */
|
||||
InvalidDBList = -67681, /* An invalid DB list was encountered. */
|
||||
InvalidPassthroughID = -67682, /* An invalid passthrough ID was encountered. */
|
||||
InvalidNetworkAddress = -67683, /* An invalid network address was encountered. */
|
||||
CRLAlreadySigned = -67684, /* The certificate revocation list is already signed. */
|
||||
InvalidNumberOfFields = -67685, /* An invalid number of fields were encountered. */
|
||||
VerificationFailure = -67686, /* A verification failure occurred. */
|
||||
UnknownTag = -67687, /* An unknown tag was encountered. */
|
||||
InvalidSignature = -67688, /* An invalid signature was encountered. */
|
||||
InvalidName = -67689, /* An invalid name was encountered. */
|
||||
InvalidCertificateRef = -67690, /* An invalid certificate reference was encountered. */
|
||||
InvalidCertificateGroup = -67691, /* An invalid certificate group was encountered. */
|
||||
TagNotFound = -67692, /* The specified tag was not found. */
|
||||
InvalidQuery = -67693, /* The specified query was not valid. */
|
||||
InvalidValue = -67694, /* An invalid value was detected. */
|
||||
CallbackFailed = -67695, /* A callback has failed. */
|
||||
ACLDeleteFailed = -67696, /* An ACL delete operation has failed. */
|
||||
ACLReplaceFailed = -67697, /* An ACL replace operation has failed. */
|
||||
ACLAddFailed = -67698, /* An ACL add operation has failed. */
|
||||
ACLChangeFailed = -67699, /* An ACL change operation has failed. */
|
||||
InvalidAccessCredentials = -67700, /* Invalid access credentials were encountered. */
|
||||
InvalidRecord = -67701, /* An invalid record was encountered. */
|
||||
InvalidACL = -67702, /* An invalid ACL was encountered. */
|
||||
InvalidSampleValue = -67703, /* An invalid sample value was encountered. */
|
||||
IncompatibleVersion = -67704, /* An incompatible version was encountered. */
|
||||
PrivilegeNotGranted = -67705, /* The privilege was not granted. */
|
||||
InvalidScope = -67706, /* An invalid scope was encountered. */
|
||||
PVCAlreadyConfigured = -67707, /* The PVC is already configured. */
|
||||
InvalidPVC = -67708, /* An invalid PVC was encountered. */
|
||||
EMMLoadFailed = -67709, /* The EMM load has failed. */
|
||||
EMMUnloadFailed = -67710, /* The EMM unload has failed. */
|
||||
AddinLoadFailed = -67711, /* The add-in load operation has failed. */
|
||||
InvalidKeyRef = -67712, /* An invalid key was encountered. */
|
||||
InvalidKeyHierarchy = -67713, /* An invalid key hierarchy was encountered. */
|
||||
AddinUnloadFailed = -67714, /* The add-in unload operation has failed. */
|
||||
LibraryReferenceNotFound = -67715, /* A library reference was not found. */
|
||||
InvalidAddinFunctionTable = -67716, /* An invalid add-in function table was encountered. */
|
||||
InvalidServiceMask = -67717, /* An invalid service mask was encountered. */
|
||||
ModuleNotLoaded = -67718, /* A module was not loaded. */
|
||||
InvalidSubServiceID = -67719, /* An invalid subservice ID was encountered. */
|
||||
AttributeNotInContext = -67720, /* An attribute was not in the context. */
|
||||
ModuleManagerInitializeFailed = -67721, /* A module failed to initialize. */
|
||||
ModuleManagerNotFound = -67722, /* A module was not found. */
|
||||
EventNotificationCallbackNotFound = -67723, /* An event notification callback was not found. */
|
||||
InputLengthError = -67724, /* An input length error was encountered. */
|
||||
OutputLengthError = -67725, /* An output length error was encountered. */
|
||||
PrivilegeNotSupported = -67726, /* The privilege is not supported. */
|
||||
DeviceError = -67727, /* A device error was encountered. */
|
||||
AttachHandleBusy = -67728, /* The CSP handle was busy. */
|
||||
NotLoggedIn = -67729, /* You are not logged in. */
|
||||
AlgorithmMismatch = -67730, /* An algorithm mismatch was encountered. */
|
||||
KeyUsageIncorrect = -67731, /* The key usage is incorrect. */
|
||||
KeyBlobTypeIncorrect = -67732, /* The key blob type is incorrect. */
|
||||
KeyHeaderInconsistent = -67733, /* The key header is inconsistent. */
|
||||
UnsupportedKeyFormat = -67734, /* The key header format is not supported. */
|
||||
UnsupportedKeySize = -67735, /* The key size is not supported. */
|
||||
InvalidKeyUsageMask = -67736, /* The key usage mask is not valid. */
|
||||
UnsupportedKeyUsageMask = -67737, /* The key usage mask is not supported. */
|
||||
InvalidKeyAttributeMask = -67738, /* The key attribute mask is not valid. */
|
||||
UnsupportedKeyAttributeMask = -67739, /* The key attribute mask is not supported. */
|
||||
InvalidKeyLabel = -67740, /* The key label is not valid. */
|
||||
UnsupportedKeyLabel = -67741, /* The key label is not supported. */
|
||||
InvalidKeyFormat = -67742, /* The key format is not valid. */
|
||||
UnsupportedVectorOfBuffers = -67743, /* The vector of buffers is not supported. */
|
||||
InvalidInputVector = -67744, /* The input vector is not valid. */
|
||||
InvalidOutputVector = -67745, /* The output vector is not valid. */
|
||||
InvalidContext = -67746, /* An invalid context was encountered. */
|
||||
InvalidAlgorithm = -67747, /* An invalid algorithm was encountered. */
|
||||
InvalidAttributeKey = -67748, /* A key attribute was not valid. */
|
||||
MissingAttributeKey = -67749, /* A key attribute was missing. */
|
||||
InvalidAttributeInitVector = -67750, /* An init vector attribute was not valid. */
|
||||
MissingAttributeInitVector = -67751, /* An init vector attribute was missing. */
|
||||
InvalidAttributeSalt = -67752, /* A salt attribute was not valid. */
|
||||
MissingAttributeSalt = -67753, /* A salt attribute was missing. */
|
||||
InvalidAttributePadding = -67754, /* A padding attribute was not valid. */
|
||||
MissingAttributePadding = -67755, /* A padding attribute was missing. */
|
||||
InvalidAttributeRandom = -67756, /* A random number attribute was not valid. */
|
||||
MissingAttributeRandom = -67757, /* A random number attribute was missing. */
|
||||
InvalidAttributeSeed = -67758, /* A seed attribute was not valid. */
|
||||
MissingAttributeSeed = -67759, /* A seed attribute was missing. */
|
||||
InvalidAttributePassphrase = -67760, /* A passphrase attribute was not valid. */
|
||||
MissingAttributePassphrase = -67761, /* A passphrase attribute was missing. */
|
||||
InvalidAttributeKeyLength = -67762, /* A key length attribute was not valid. */
|
||||
MissingAttributeKeyLength = -67763, /* A key length attribute was missing. */
|
||||
InvalidAttributeBlockSize = -67764, /* A block size attribute was not valid. */
|
||||
MissingAttributeBlockSize = -67765, /* A block size attribute was missing. */
|
||||
InvalidAttributeOutputSize = -67766, /* An output size attribute was not valid. */
|
||||
MissingAttributeOutputSize = -67767, /* An output size attribute was missing. */
|
||||
InvalidAttributeRounds = -67768, /* The number of rounds attribute was not valid. */
|
||||
MissingAttributeRounds = -67769, /* The number of rounds attribute was missing. */
|
||||
InvalidAlgorithmParms = -67770, /* An algorithm parameters attribute was not valid. */
|
||||
MissingAlgorithmParms = -67771, /* An algorithm parameters attribute was missing. */
|
||||
InvalidAttributeLabel = -67772, /* A label attribute was not valid. */
|
||||
MissingAttributeLabel = -67773, /* A label attribute was missing. */
|
||||
InvalidAttributeKeyType = -67774, /* A key type attribute was not valid. */
|
||||
MissingAttributeKeyType = -67775, /* A key type attribute was missing. */
|
||||
InvalidAttributeMode = -67776, /* A mode attribute was not valid. */
|
||||
MissingAttributeMode = -67777, /* A mode attribute was missing. */
|
||||
InvalidAttributeEffectiveBits = -67778, /* An effective bits attribute was not valid. */
|
||||
MissingAttributeEffectiveBits = -67779, /* An effective bits attribute was missing. */
|
||||
InvalidAttributeStartDate = -67780, /* A start date attribute was not valid. */
|
||||
MissingAttributeStartDate = -67781, /* A start date attribute was missing. */
|
||||
InvalidAttributeEndDate = -67782, /* An end date attribute was not valid. */
|
||||
MissingAttributeEndDate = -67783, /* An end date attribute was missing. */
|
||||
InvalidAttributeVersion = -67784, /* A version attribute was not valid. */
|
||||
MissingAttributeVersion = -67785, /* A version attribute was missing. */
|
||||
InvalidAttributePrime = -67786, /* A prime attribute was not valid. */
|
||||
MissingAttributePrime = -67787, /* A prime attribute was missing. */
|
||||
InvalidAttributeBase = -67788, /* A base attribute was not valid. */
|
||||
MissingAttributeBase = -67789, /* A base attribute was missing. */
|
||||
InvalidAttributeSubprime = -67790, /* A subprime attribute was not valid. */
|
||||
MissingAttributeSubprime = -67791, /* A subprime attribute was missing. */
|
||||
InvalidAttributeIterationCount = -67792, /* An iteration count attribute was not valid. */
|
||||
MissingAttributeIterationCount = -67793, /* An iteration count attribute was missing. */
|
||||
InvalidAttributeDLDBHandle = -67794, /* A database handle attribute was not valid. */
|
||||
MissingAttributeDLDBHandle = -67795, /* A database handle attribute was missing. */
|
||||
InvalidAttributeAccessCredentials = -67796, /* An access credentials attribute was not valid. */
|
||||
MissingAttributeAccessCredentials = -67797, /* An access credentials attribute was missing. */
|
||||
InvalidAttributePublicKeyFormat = -67798, /* A public key format attribute was not valid. */
|
||||
MissingAttributePublicKeyFormat = -67799, /* A public key format attribute was missing. */
|
||||
InvalidAttributePrivateKeyFormat = -67800, /* A private key format attribute was not valid. */
|
||||
MissingAttributePrivateKeyFormat = -67801, /* A private key format attribute was missing. */
|
||||
InvalidAttributeSymmetricKeyFormat = -67802, /* A symmetric key format attribute was not valid. */
|
||||
MissingAttributeSymmetricKeyFormat = -67803, /* A symmetric key format attribute was missing. */
|
||||
InvalidAttributeWrappedKeyFormat = -67804, /* A wrapped key format attribute was not valid. */
|
||||
MissingAttributeWrappedKeyFormat = -67805, /* A wrapped key format attribute was missing. */
|
||||
StagedOperationInProgress = -67806, /* A staged operation is in progress. */
|
||||
StagedOperationNotStarted = -67807, /* A staged operation was not started. */
|
||||
VerifyFailed = -67808, /* A cryptographic verification failure has occurred. */
|
||||
QuerySizeUnknown = -67809, /* The query size is unknown. */
|
||||
BlockSizeMismatch = -67810, /* A block size mismatch occurred. */
|
||||
PublicKeyInconsistent = -67811, /* The public key was inconsistent. */
|
||||
DeviceVerifyFailed = -67812, /* A device verification failure has occurred. */
|
||||
InvalidLoginName = -67813, /* An invalid login name was detected. */
|
||||
AlreadyLoggedIn = -67814, /* The user is already logged in. */
|
||||
InvalidDigestAlgorithm = -67815, /* An invalid digest algorithm was detected. */
|
||||
InvalidCRLGroup = -67816, /* An invalid CRL group was detected. */
|
||||
CertificateCannotOperate = -67817, /* The certificate cannot operate. */
|
||||
CertificateExpired = -67818, /* An expired certificate was detected. */
|
||||
CertificateNotValidYet = -67819, /* The certificate is not yet valid. */
|
||||
CertificateRevoked = -67820, /* The certificate was revoked. */
|
||||
CertificateSuspended = -67821, /* The certificate was suspended. */
|
||||
InsufficientCredentials = -67822, /* Insufficient credentials were detected. */
|
||||
InvalidAction = -67823, /* The action was not valid. */
|
||||
InvalidAuthority = -67824, /* The authority was not valid. */
|
||||
VerifyActionFailed = -67825, /* A verify action has failed. */
|
||||
InvalidCertAuthority = -67826, /* The certificate authority was not valid. */
|
||||
InvalidCRLAuthority = -67827, /* The CRL authority was not valid. */
|
||||
#if MONOMAC
|
||||
[Obsolete ("Use InvalidCRLAuthority")]
|
||||
InvaldCRLAuthority = InvalidCRLAuthority,
|
||||
#endif
|
||||
InvalidCRLEncoding = -67828, /* The CRL encoding was not valid. */
|
||||
InvalidCRLType = -67829, /* The CRL type was not valid. */
|
||||
InvalidCRL = -67830, /* The CRL was not valid. */
|
||||
InvalidFormType = -67831, /* The form type was not valid. */
|
||||
InvalidID = -67832, /* The ID was not valid. */
|
||||
InvalidIdentifier = -67833, /* The identifier was not valid. */
|
||||
InvalidIndex = -67834, /* The index was not valid. */
|
||||
InvalidPolicyIdentifiers = -67835, /* The policy identifiers are not valid. */
|
||||
InvalidTimeString = -67836, /* The time specified was not valid. */
|
||||
InvalidReason = -67837, /* The trust policy reason was not valid. */
|
||||
InvalidRequestInputs = -67838, /* The request inputs are not valid. */
|
||||
InvalidResponseVector = -67839, /* The response vector was not valid. */
|
||||
InvalidStopOnPolicy = -67840, /* The stop-on policy was not valid. */
|
||||
InvalidTuple = -67841, /* The tuple was not valid. */
|
||||
MultipleValuesUnsupported = -67842, /* Multiple values are not supported. */
|
||||
NotTrusted = -67843, /* The trust policy was not trusted. */
|
||||
NoDefaultAuthority = -67844, /* No default authority was detected. */
|
||||
RejectedForm = -67845, /* The trust policy had a rejected form. */
|
||||
RequestLost = -67846, /* The request was lost. */
|
||||
RequestRejected = -67847, /* The request was rejected. */
|
||||
UnsupportedAddressType = -67848, /* The address type is not supported. */
|
||||
UnsupportedService = -67849, /* The service is not supported. */
|
||||
InvalidTupleGroup = -67850, /* The tuple group was not valid. */
|
||||
InvalidBaseACLs = -67851, /* The base ACLs are not valid. */
|
||||
InvalidTupleCredentials = -67852, /* The tuple credentials are not valid. */
|
||||
#if MONOMAC
|
||||
[Obsolete ("Use InvalidTupleCredentials")]
|
||||
InvalidTupleCredendtials = InvalidTupleCredentials,
|
||||
#endif
|
||||
InvalidEncoding = -67853, /* The encoding was not valid. */
|
||||
InvalidValidityPeriod = -67854, /* The validity period was not valid. */
|
||||
InvalidRequestor = -67855, /* The requestor was not valid. */
|
||||
RequestDescriptor = -67856, /* The request descriptor was not valid. */
|
||||
InvalidBundleInfo = -67857, /* The bundle information was not valid. */
|
||||
InvalidCRLIndex = -67858, /* The CRL index was not valid. */
|
||||
NoFieldValues = -67859, /* No field values were detected. */
|
||||
UnsupportedFieldFormat = -67860, /* The field format is not supported. */
|
||||
UnsupportedIndexInfo = -67861, /* The index information is not supported. */
|
||||
UnsupportedLocality = -67862, /* The locality is not supported. */
|
||||
UnsupportedNumAttributes = -67863, /* The number of attributes is not supported. */
|
||||
UnsupportedNumIndexes = -67864, /* The number of indexes is not supported. */
|
||||
UnsupportedNumRecordTypes = -67865, /* The number of record types is not supported. */
|
||||
FieldSpecifiedMultiple = -67866, /* Too many fields were specified. */
|
||||
IncompatibleFieldFormat = -67867, /* The field format was incompatible. */
|
||||
InvalidParsingModule = -67868, /* The parsing module was not valid. */
|
||||
DatabaseLocked = -67869, /* The database is locked. */
|
||||
DatastoreIsOpen = -67870, /* The data store is open. */
|
||||
MissingValue = -67871, /* A missing value was detected. */
|
||||
UnsupportedQueryLimits = -67872, /* The query limits are not supported. */
|
||||
UnsupportedNumSelectionPreds = -67873, /* The number of selection predicates is not supported. */
|
||||
UnsupportedOperator = -67874, /* The operator is not supported. */
|
||||
InvalidDBLocation = -67875, /* The database location is not valid. */
|
||||
InvalidAccessRequest = -67876, /* The access request is not valid. */
|
||||
InvalidIndexInfo = -67877, /* The index information is not valid. */
|
||||
InvalidNewOwner = -67878, /* The new owner is not valid. */
|
||||
InvalidModifyMode = -67879, /* The modify mode is not valid. */
|
||||
MissingRequiredExtension = -67880, /* A required certificate extension is missing. */
|
||||
ExtendedKeyUsageNotCritical = -67881, /* The extended key usage extension was not marked critical. */
|
||||
TimestampMissing = -67882, /* A timestamp was expected but was not found. */
|
||||
TimestampInvalid = -67883, /* The timestamp was not valid. */
|
||||
TimestampNotTrusted = -67884, /* The timestamp was not trusted. */
|
||||
TimestampServiceNotAvailable = -67885, /* The timestamp service is not available. */
|
||||
TimestampBadAlg = -67886, /* An unrecognized or unsupported Algorithm Identifier in timestamp. */
|
||||
TimestampBadRequest = -67887, /* The timestamp transaction is not permitted or supported. */
|
||||
TimestampBadDataFormat = -67888, /* The timestamp data submitted has the wrong format. */
|
||||
TimestampTimeNotAvailable = -67889, /* The time source for the Timestamp Authority is not available. */
|
||||
TimestampUnacceptedPolicy = -67890, /* The requested policy is not supported by the Timestamp Authority. */
|
||||
TimestampUnacceptedExtension = -67891, /* The requested extension is not supported by the Timestamp Authority. */
|
||||
TimestampAddInfoNotAvailable = -67892, /* The additional information requested is not available. */
|
||||
TimestampSystemFailure = -67893, /* The timestamp request cannot be handled due to system failure. */
|
||||
SigningTimeMissing = -67894, /* A signing time was expected but was not found. */
|
||||
TimestampRejection = -67895, /* A timestamp transaction was rejected. */
|
||||
TimestampWaiting = -67896, /* A timestamp transaction is waiting. */
|
||||
TimestampRevocationWarning = -67897, /* A timestamp authority revocation warning was issued. */
|
||||
TimestampRevocationNotification = -67898, /* A timestamp authority revocation notification was issued. */
|
||||
}
|
||||
|
||||
// typedef uint32_t SecTrustResultType;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if SECURITY_DEP && MONO_FEATURE_APPLETLS
|
||||
#if SECURITY_DEP && MONO_FEATURE_APPLETLS
|
||||
//
|
||||
// ImportExport.cs
|
||||
//
|
||||
@ -29,9 +29,17 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using ObjCRuntime;
|
||||
using Mono.Net;
|
||||
|
||||
#if MONO_FEATURE_BTLS
|
||||
using Mono.Btls;
|
||||
#else
|
||||
using Mono.Security.Cryptography;
|
||||
#endif
|
||||
|
||||
namespace Mono.AppleTls {
|
||||
|
||||
internal partial class SecImportExport {
|
||||
@ -54,9 +62,163 @@ namespace Mono.AppleTls {
|
||||
IntPtr handle;
|
||||
SecStatusCode code = SecPKCS12Import (data.Handle, options.Handle, out handle);
|
||||
array = CFArray.ArrayFromHandle <CFDictionary> (handle, h => new CFDictionary (h, false));
|
||||
CFObject.CFRelease (handle);
|
||||
if (handle != IntPtr.Zero)
|
||||
CFObject.CFRelease (handle);
|
||||
return code;
|
||||
}
|
||||
|
||||
#if !MONOTOUCH
|
||||
[DllImport (AppleTlsContext.SecurityLibrary)]
|
||||
extern static SecStatusCode SecItemImport (
|
||||
/* CFDataRef */ IntPtr importedData,
|
||||
/* CFStringRef */ IntPtr fileNameOrExtension, // optional
|
||||
/* SecExternalFormat* */ ref SecExternalFormat inputFormat, // optional, IN/OUT
|
||||
/* SecExternalItemType* */ ref SecExternalItemType itemType, // optional, IN/OUT
|
||||
/* SecItemImportExportFlags */ SecItemImportExportFlags flags,
|
||||
/* const SecItemImportExportKeyParameters* */ IntPtr keyParams, // optional
|
||||
/* SecKeychainRef */ IntPtr importKeychain, // optional
|
||||
/* CFArrayRef* */ out IntPtr outItems);
|
||||
|
||||
static public CFArray ItemImport (byte[] buffer, string password)
|
||||
{
|
||||
using (var data = CFData.FromData (buffer))
|
||||
using (var pwstring = CFString.Create (password)) {
|
||||
SecItemImportExportKeyParameters keyParams = new SecItemImportExportKeyParameters ();
|
||||
keyParams.passphrase = pwstring.Handle;
|
||||
|
||||
return ItemImport (data, SecExternalFormat.PKCS12, SecExternalItemType.Aggregate, SecItemImportExportFlags.None, keyParams);
|
||||
}
|
||||
}
|
||||
|
||||
static CFArray ItemImport (CFData data, SecExternalFormat format, SecExternalItemType itemType,
|
||||
SecItemImportExportFlags flags = SecItemImportExportFlags.None,
|
||||
SecItemImportExportKeyParameters? keyParams = null)
|
||||
{
|
||||
return ItemImport (data, ref format, ref itemType, flags, keyParams);
|
||||
}
|
||||
|
||||
static CFArray ItemImport (CFData data, ref SecExternalFormat format, ref SecExternalItemType itemType,
|
||||
SecItemImportExportFlags flags = SecItemImportExportFlags.None,
|
||||
SecItemImportExportKeyParameters? keyParams = null)
|
||||
{
|
||||
IntPtr keyParamsPtr = IntPtr.Zero;
|
||||
if (keyParams != null) {
|
||||
keyParamsPtr = Marshal.AllocHGlobal (Marshal.SizeOf (keyParams.Value));
|
||||
if (keyParamsPtr == IntPtr.Zero)
|
||||
throw new OutOfMemoryException ();
|
||||
Marshal.StructureToPtr (keyParams.Value, keyParamsPtr, false);
|
||||
}
|
||||
|
||||
IntPtr result;
|
||||
var status = SecItemImport (data.Handle, IntPtr.Zero, ref format, ref itemType, flags, keyParamsPtr, IntPtr.Zero, out result);
|
||||
|
||||
if (keyParamsPtr != IntPtr.Zero)
|
||||
Marshal.FreeHGlobal (keyParamsPtr);
|
||||
|
||||
if (status != SecStatusCode.Success)
|
||||
throw new NotSupportedException (status.ToString ());
|
||||
|
||||
return new CFArray (result, true);
|
||||
}
|
||||
|
||||
[DllImport (AppleTlsContext.SecurityLibrary)]
|
||||
extern static /* SecIdentityRef */ IntPtr SecIdentityCreate (
|
||||
/* CFAllocatorRef */ IntPtr allocator,
|
||||
/* SecCertificateRef */ IntPtr certificate,
|
||||
/* SecKeyRef */ IntPtr privateKey);
|
||||
|
||||
static public SecIdentity ItemImport (X509Certificate2 certificate)
|
||||
{
|
||||
if (!certificate.HasPrivateKey)
|
||||
throw new NotSupportedException ();
|
||||
|
||||
using (var key = ImportPrivateKey (certificate))
|
||||
using (var cert = new SecCertificate (certificate)) {
|
||||
var identity = SecIdentityCreate (IntPtr.Zero, cert.Handle, key.Handle);
|
||||
if (CFType.GetTypeID (identity) != SecIdentity.GetTypeID ())
|
||||
throw new InvalidOperationException ();
|
||||
|
||||
return new SecIdentity (identity, true);
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] ExportKey (RSA key)
|
||||
{
|
||||
#if MONO_FEATURE_BTLS
|
||||
using (var btlsKey = MonoBtlsKey.CreateFromRSAPrivateKey (key))
|
||||
return btlsKey.GetBytes (true);
|
||||
#else
|
||||
return PKCS8.PrivateKeyInfo.Encode (key);
|
||||
#endif
|
||||
}
|
||||
|
||||
static SecKey ImportPrivateKey (X509Certificate2 certificate)
|
||||
{
|
||||
if (!certificate.HasPrivateKey)
|
||||
throw new NotSupportedException ();
|
||||
|
||||
CFArray items;
|
||||
using (var data = CFData.FromData (ExportKey ((RSA)certificate.PrivateKey)))
|
||||
items = ItemImport (data, SecExternalFormat.OpenSSL, SecExternalItemType.PrivateKey);
|
||||
|
||||
try {
|
||||
if (items.Count != 1)
|
||||
throw new InvalidOperationException ("Private key import failed.");
|
||||
|
||||
var imported = items[0];
|
||||
if (CFType.GetTypeID (imported) != SecKey.GetTypeID ())
|
||||
throw new InvalidOperationException ("Private key import doesn't return SecKey.");
|
||||
|
||||
return new SecKey (imported, items.Handle);
|
||||
} finally {
|
||||
items.Dispose ();
|
||||
}
|
||||
}
|
||||
|
||||
const int SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION = 0;
|
||||
|
||||
// Native enum; don't change.
|
||||
enum SecExternalFormat : int {
|
||||
Unknown = 0,
|
||||
OpenSSL = 1,
|
||||
X509Cert = 9,
|
||||
PEMSequence = 10,
|
||||
PKCS7 = 11,
|
||||
PKCS12 = 12
|
||||
}
|
||||
|
||||
// Native enum; don't change.
|
||||
enum SecExternalItemType : int {
|
||||
Unknown = 0,
|
||||
PrivateKey = 1,
|
||||
PublicKey = 2,
|
||||
SessionKey = 3,
|
||||
Certificate = 4,
|
||||
Aggregate = 5
|
||||
}
|
||||
|
||||
// Native enum; don't change
|
||||
enum SecItemImportExportFlags : int {
|
||||
None,
|
||||
PemArmour = 0x00000001, /* exported blob is PEM formatted */
|
||||
}
|
||||
|
||||
// Native struct; don't change
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
struct SecItemImportExportKeyParameters {
|
||||
public int version; /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */
|
||||
public int flags; /* SecKeyImportExportFlags bits */
|
||||
public IntPtr passphrase; /* SecExternalFormat.PKCS12 only. Legal types are CFStringRef and CFDataRef. */
|
||||
|
||||
IntPtr alertTitle;
|
||||
IntPtr alertPrompt;
|
||||
|
||||
public IntPtr accessRef; /* SecAccessRef */
|
||||
|
||||
IntPtr keyUsage;
|
||||
IntPtr keyAttributes;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if SECURITY_DEP && MONO_FEATURE_APPLETLS
|
||||
#if SECURITY_DEP && MONO_FEATURE_APPLETLS
|
||||
//
|
||||
// Items.cs: Implements the KeyChain query access APIs
|
||||
//
|
||||
@ -40,13 +40,32 @@ using Mono.Net;
|
||||
namespace Mono.AppleTls {
|
||||
|
||||
enum SecKind {
|
||||
Identity
|
||||
Identity,
|
||||
Certificate
|
||||
}
|
||||
|
||||
#if MONOTOUCH
|
||||
static class SecKeyChain {
|
||||
static readonly IntPtr MatchLimitAll;
|
||||
static readonly IntPtr MatchLimitOne;
|
||||
static readonly IntPtr MatchLimit;
|
||||
#else
|
||||
class SecKeyChain : INativeObject, IDisposable {
|
||||
#endif
|
||||
internal static readonly IntPtr MatchLimitAll;
|
||||
internal static readonly IntPtr MatchLimitOne;
|
||||
internal static readonly IntPtr MatchLimit;
|
||||
|
||||
#if !MONOTOUCH
|
||||
IntPtr handle;
|
||||
|
||||
internal SecKeyChain (IntPtr handle, bool owns = false)
|
||||
{
|
||||
if (handle == IntPtr.Zero)
|
||||
throw new ArgumentException ("Invalid handle");
|
||||
|
||||
this.handle = handle;
|
||||
if (!owns)
|
||||
CFObject.CFRetain (handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SecKeyChain ()
|
||||
{
|
||||
@ -98,39 +117,47 @@ namespace Mono.AppleTls {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static INativeObject[] QueryAsReference (SecRecord query, int max, out SecStatusCode result)
|
||||
|
||||
static INativeObject [] QueryAsReference (SecRecord query, int max, out SecStatusCode result)
|
||||
{
|
||||
if (query == null){
|
||||
if (query == null) {
|
||||
result = SecStatusCode.Param;
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var copy = query.queryDict.MutableCopy ()) {
|
||||
using (var copy = query.QueryDict.MutableCopy ()) {
|
||||
copy.SetValue (CFBoolean.True.Handle, SecItem.ReturnRef);
|
||||
SetLimit (copy, max);
|
||||
|
||||
IntPtr ptr;
|
||||
result = SecItem.SecItemCopyMatching (copy.Handle, out ptr);
|
||||
if ((result == SecStatusCode.Success) && (ptr != IntPtr.Zero)) {
|
||||
var array = CFArray.ArrayFromHandle<INativeObject> (ptr, p => {
|
||||
IntPtr cfType = CFType.GetTypeID (p);
|
||||
if (cfType == SecCertificate.GetTypeID ())
|
||||
return new SecCertificate (p, true);
|
||||
else if (cfType == SecKey.GetTypeID ())
|
||||
return new SecKey (p, true);
|
||||
else if (cfType == SecIdentity.GetTypeID ())
|
||||
return new SecIdentity (p, true);
|
||||
else
|
||||
throw new Exception (String.Format ("Unexpected type: 0x{0:x}", cfType));
|
||||
});
|
||||
return array;
|
||||
}
|
||||
return null;
|
||||
return QueryAsReference (copy, out result);
|
||||
}
|
||||
}
|
||||
|
||||
static CFNumber SetLimit (CFMutableDictionary dict, int max)
|
||||
static INativeObject [] QueryAsReference (CFDictionary query, out SecStatusCode result)
|
||||
{
|
||||
if (query == null) {
|
||||
result = SecStatusCode.Param;
|
||||
return null;
|
||||
}
|
||||
|
||||
IntPtr ptr;
|
||||
result = SecItem.SecItemCopyMatching (query.Handle, out ptr);
|
||||
if (result == SecStatusCode.Success && ptr != IntPtr.Zero) {
|
||||
var array = CFArray.ArrayFromHandle<INativeObject> (ptr, p => {
|
||||
IntPtr cfType = CFType.GetTypeID (p);
|
||||
if (cfType == SecCertificate.GetTypeID ())
|
||||
return new SecCertificate (p, true);
|
||||
if (cfType == SecKey.GetTypeID ())
|
||||
return new SecKey (p, true);
|
||||
if (cfType == SecIdentity.GetTypeID ())
|
||||
return new SecIdentity (p, true);
|
||||
throw new Exception (String.Format ("Unexpected type: 0x{0:x}", cfType));
|
||||
});
|
||||
return array;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static CFNumber SetLimit (CFMutableDictionary dict, int max)
|
||||
{
|
||||
CFNumber n = null;
|
||||
IntPtr val;
|
||||
@ -142,47 +169,61 @@ namespace Mono.AppleTls {
|
||||
n = CFNumber.FromInt32 (max);
|
||||
val = n.Handle;
|
||||
}
|
||||
|
||||
|
||||
dict.SetValue (val, SecKeyChain.MatchLimit);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
class SecRecord : IDisposable {
|
||||
|
||||
static readonly IntPtr SecClassKey;
|
||||
static SecRecord ()
|
||||
#if !MONOTOUCH
|
||||
[DllImport (AppleTlsContext.SecurityLibrary)]
|
||||
extern static /* OSStatus */ SecStatusCode SecKeychainCreate (/* const char * */ IntPtr pathName, uint passwordLength, /* const void * */ IntPtr password,
|
||||
bool promptUser, /* SecAccessRef */ IntPtr initialAccess,
|
||||
/* SecKeychainRef _Nullable * */ out IntPtr keychain);
|
||||
|
||||
internal static SecKeyChain Create (string pathName, string password)
|
||||
{
|
||||
var handle = CFObject.dlopen (AppleTlsContext.SecurityLibrary, 0);
|
||||
if (handle == IntPtr.Zero)
|
||||
return;
|
||||
IntPtr handle;
|
||||
var pathNamePtr = Marshal.StringToHGlobalAnsi (pathName);
|
||||
var passwordPtr = Marshal.StringToHGlobalAnsi (password);
|
||||
var result = SecKeychainCreate (pathNamePtr, (uint)password.Length, passwordPtr, false, IntPtr.Zero, out handle);
|
||||
if (result != SecStatusCode.Success)
|
||||
throw new InvalidOperationException (result.ToString ());
|
||||
return new SecKeyChain (handle, true);
|
||||
}
|
||||
|
||||
try {
|
||||
SecClassKey = CFObject.GetIntPtr (handle, "kSecClassKey");
|
||||
[DllImport (AppleTlsContext.SecurityLibrary)]
|
||||
extern static /* OSStatus */ SecStatusCode SecKeychainOpen (/* const char * */ IntPtr pathName, /* SecKeychainRef _Nullable * */ out IntPtr keychain);
|
||||
|
||||
internal static SecKeyChain Open (string pathName)
|
||||
{
|
||||
IntPtr handle;
|
||||
IntPtr pathNamePtr = IntPtr.Zero;
|
||||
try {
|
||||
pathNamePtr = Marshal.StringToHGlobalAnsi (pathName);
|
||||
var result = SecKeychainOpen (pathNamePtr, out handle);
|
||||
if (result != SecStatusCode.Success)
|
||||
throw new InvalidOperationException (result.ToString ());
|
||||
return new SecKeyChain (handle, true);
|
||||
} finally {
|
||||
CFObject.dlclose (handle);
|
||||
if (pathNamePtr != IntPtr.Zero)
|
||||
Marshal.FreeHGlobal (pathNamePtr);
|
||||
}
|
||||
}
|
||||
|
||||
// Fix <= iOS 6 Behaviour - Desk #83099
|
||||
// NSCFDictionary: mutating method sent to immutable object
|
||||
// iOS 6 returns an inmutable NSDictionary handle and when we try to set its values it goes kaboom
|
||||
// By explicitly calling `MutableCopy` we ensure we always have a mutable reference we expect that.
|
||||
CFDictionary _queryDict;
|
||||
internal CFDictionary queryDict
|
||||
{
|
||||
get {
|
||||
return _queryDict;
|
||||
}
|
||||
set {
|
||||
_queryDict = value != null ? value.Copy () : null;
|
||||
}
|
||||
}
|
||||
|
||||
public SecRecord (SecKind secKind)
|
||||
internal static SecKeyChain OpenSystemRootCertificates ()
|
||||
{
|
||||
var kind = SecClass.FromSecKind (secKind);
|
||||
queryDict = CFDictionary.FromObjectAndKey (kind, SecClassKey);
|
||||
return Open ("/System/Library/Keychains/SystemRootCertificates.keychain");
|
||||
}
|
||||
|
||||
~SecKeyChain ()
|
||||
{
|
||||
Dispose (false);
|
||||
}
|
||||
|
||||
public IntPtr Handle {
|
||||
get {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
@ -193,10 +234,61 @@ namespace Mono.AppleTls {
|
||||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (queryDict != null){
|
||||
if (handle != IntPtr.Zero) {
|
||||
CFObject.CFRelease (handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
class SecRecord : IDisposable {
|
||||
|
||||
internal static readonly IntPtr SecClassKey;
|
||||
static SecRecord ()
|
||||
{
|
||||
var handle = CFObject.dlopen (AppleTlsContext.SecurityLibrary, 0);
|
||||
if (handle == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
try {
|
||||
SecClassKey = CFObject.GetIntPtr (handle, "kSecClass");
|
||||
} finally {
|
||||
CFObject.dlclose (handle);
|
||||
}
|
||||
}
|
||||
|
||||
CFMutableDictionary _queryDict;
|
||||
internal CFMutableDictionary QueryDict {
|
||||
get {
|
||||
return _queryDict;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetValue (IntPtr key, IntPtr value)
|
||||
{
|
||||
_queryDict.SetValue (key, value);
|
||||
}
|
||||
|
||||
public SecRecord (SecKind secKind)
|
||||
{
|
||||
var kind = SecClass.FromSecKind (secKind);
|
||||
_queryDict = CFMutableDictionary.Create ();
|
||||
_queryDict.SetValue (SecClassKey, kind);
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (_queryDict != null){
|
||||
if (disposing){
|
||||
queryDict.Dispose ();
|
||||
queryDict = null;
|
||||
_queryDict.Dispose ();
|
||||
_queryDict = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -209,6 +301,7 @@ namespace Mono.AppleTls {
|
||||
|
||||
partial class SecItem {
|
||||
public static readonly IntPtr ReturnRef;
|
||||
public static readonly IntPtr MatchSearchList;
|
||||
|
||||
static SecItem ()
|
||||
{
|
||||
@ -218,6 +311,7 @@ namespace Mono.AppleTls {
|
||||
|
||||
try {
|
||||
ReturnRef = CFObject.GetIntPtr (handle, "kSecReturnRef");
|
||||
MatchSearchList = CFObject.GetIntPtr (handle, "kSecMatchSearchList");
|
||||
} finally {
|
||||
CFObject.dlclose (handle);
|
||||
}
|
||||
@ -230,6 +324,7 @@ namespace Mono.AppleTls {
|
||||
static partial class SecClass {
|
||||
|
||||
public static readonly IntPtr Identity;
|
||||
public static readonly IntPtr Certificate;
|
||||
|
||||
static SecClass ()
|
||||
{
|
||||
@ -237,8 +332,9 @@ namespace Mono.AppleTls {
|
||||
if (handle == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
try {
|
||||
try {
|
||||
Identity = CFObject.GetIntPtr (handle, "kSecClassIdentity");
|
||||
Certificate = CFObject.GetIntPtr (handle, "kSecClassCertificate");
|
||||
} finally {
|
||||
CFObject.dlclose (handle);
|
||||
}
|
||||
@ -249,6 +345,8 @@ namespace Mono.AppleTls {
|
||||
switch (secKind){
|
||||
case SecKind.Identity:
|
||||
return Identity;
|
||||
case SecKind.Certificate:
|
||||
return Certificate;
|
||||
default:
|
||||
throw new ArgumentException ("secKind");
|
||||
}
|
||||
|
@ -469,7 +469,18 @@ namespace Mono.Net
|
||||
{
|
||||
return new CFDictionary (CFDictionaryCreate (IntPtr.Zero, new IntPtr[] { key }, new IntPtr [] { obj }, (IntPtr)1, KeyCallbacks, ValueCallbacks), true);
|
||||
}
|
||||
|
||||
|
||||
public static CFDictionary FromKeysAndObjects (IList<Tuple<IntPtr,IntPtr>> items)
|
||||
{
|
||||
var keys = new IntPtr [items.Count];
|
||||
var values = new IntPtr [items.Count];
|
||||
for (int i = 0; i < items.Count; i++) {
|
||||
keys [i] = items [i].Item1;
|
||||
values [i] = items [i].Item2;
|
||||
}
|
||||
return new CFDictionary (CFDictionaryCreate (IntPtr.Zero, keys, values, (IntPtr)items.Count, KeyCallbacks, ValueCallbacks), true);
|
||||
}
|
||||
|
||||
[DllImport (CoreFoundationLibrary)]
|
||||
extern static IntPtr CFDictionaryCreate (IntPtr allocator, IntPtr[] keys, IntPtr[] vals, IntPtr len, IntPtr keyCallbacks, IntPtr valCallbacks);
|
||||
|
||||
@ -513,8 +524,20 @@ namespace Mono.Net
|
||||
CFDictionarySetValue (Handle, key, val);
|
||||
}
|
||||
|
||||
public static CFMutableDictionary Create ()
|
||||
{
|
||||
var handle = CFDictionaryCreateMutable (IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
if (handle == IntPtr.Zero)
|
||||
throw new InvalidOperationException ();
|
||||
return new CFMutableDictionary (handle, true);
|
||||
}
|
||||
|
||||
[DllImport (CoreFoundationLibrary)]
|
||||
extern static void CFDictionarySetValue (IntPtr handle, IntPtr key, IntPtr val);
|
||||
|
||||
[DllImport (CoreFoundationLibrary)]
|
||||
extern static IntPtr CFDictionaryCreateMutable (IntPtr allocator, IntPtr capacity, IntPtr keyCallback, IntPtr valueCallbacks);
|
||||
|
||||
}
|
||||
|
||||
internal class CFUrl : CFObject
|
||||
|
@ -1016,6 +1016,18 @@ namespace System.Net
|
||||
IAsyncResult result = null;
|
||||
try {
|
||||
result = s.BeginWrite (buffer, offset, size, cb, state);
|
||||
} catch (ObjectDisposedException) {
|
||||
lock (this) {
|
||||
if (Data.request != request)
|
||||
return null;
|
||||
}
|
||||
throw;
|
||||
} catch (IOException e) {
|
||||
SocketException se = e.InnerException as SocketException;
|
||||
if (se != null && se.SocketErrorCode == SocketError.NotConnected) {
|
||||
return null;
|
||||
}
|
||||
throw;
|
||||
} catch (Exception) {
|
||||
status = WebExceptionStatus.SendFailure;
|
||||
throw;
|
||||
|
@ -1 +1 @@
|
||||
08d4642d4dfb3cb6a43b58d442f02e11e747742b
|
||||
9730a8aa4510c1e02ddaf93e1b0858f961a19d27
|
@ -435,6 +435,9 @@ mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrAr
|
||||
if (sfiles)
|
||||
g_ptr_array_add (sfiles, docinfo);
|
||||
|
||||
if (source_file)
|
||||
*source_file = g_strdup (docinfo->source_file);
|
||||
|
||||
iloffset = 0;
|
||||
start_line = 0;
|
||||
start_col = 0;
|
||||
@ -492,8 +495,6 @@ mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrAr
|
||||
memcpy (*seq_points, sps->data, sps->len * sizeof (MonoSymSeqPoint));
|
||||
}
|
||||
|
||||
if (source_file)
|
||||
*source_file = g_strdup (((MonoDebugSourceInfo*)g_ptr_array_index (sfiles, 0))->source_file);
|
||||
if (source_files) {
|
||||
*source_files = g_new (int, sps->len);
|
||||
for (i = 0; i < sps->len; ++i)
|
||||
|
@ -878,7 +878,7 @@ EXTRA_DIST = TestDriver.cs \
|
||||
Makefile.am.in
|
||||
|
||||
version.h: Makefile
|
||||
echo "#define FULL_VERSION \"Stable 5.0.0.48/851b6c7\"" > version.h
|
||||
echo "#define FULL_VERSION \"Stable 5.0.0.61/4242008\"" > version.h
|
||||
|
||||
# Utility target for patching libtool to speed up linking
|
||||
patch-libtool:
|
||||
|
@ -878,7 +878,7 @@ EXTRA_DIST = TestDriver.cs \
|
||||
Makefile.am.in
|
||||
|
||||
version.h: Makefile
|
||||
echo "#define FULL_VERSION \"Stable 5.0.0.48/851b6c7\"" > version.h
|
||||
echo "#define FULL_VERSION \"Stable 5.0.0.61/4242008\"" > version.h
|
||||
|
||||
# Utility target for patching libtool to speed up linking
|
||||
patch-libtool:
|
||||
|
@ -1 +1 @@
|
||||
6cfc9c6b9b9f5d22de9a650e7d5527a33b533cca
|
||||
434fe4e634a1bfba7eb1b7d400bb980490f1e895
|
@ -1 +1 @@
|
||||
c61a76885b8fb2ba68708558b39487a7d53e1f9c
|
||||
c3ec223220f37f6e77b2a9b2e9b02a82c06da77c
|
@ -217,8 +217,8 @@ mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_si
|
||||
else
|
||||
src_slot = map_stack_slot (ainfo->offset / 4);
|
||||
g_assert (ndst < 256);
|
||||
g_assert (src_slot < 16);
|
||||
src [0] = (ndst << 4) | src_slot;
|
||||
g_assert (src_slot < 256);
|
||||
src [0] = (ndst << 8) | src_slot;
|
||||
|
||||
if (ainfo2->storage == RegTypeGeneral && ainfo2->size != 0 && ainfo2->size != 4) {
|
||||
/* Have to load less than 4 bytes */
|
||||
@ -256,7 +256,7 @@ mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_si
|
||||
ndst = get_arg_slots (ainfo2, &dst);
|
||||
}
|
||||
if (nsrc)
|
||||
src [0] |= (arg_marshal << 16);
|
||||
src [0] |= (arg_marshal << 24);
|
||||
nslots = MIN (nsrc, ndst);
|
||||
|
||||
for (i = 0; i < nslots; ++i)
|
||||
|
@ -53,7 +53,7 @@ mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpoint
|
||||
for (i = 0; i < info->map_count; ++i) {
|
||||
int src = info->map [i * 2];
|
||||
int dst = info->map [(i * 2) + 1];
|
||||
int arg_marshal = (src >> 16) & 0xff;
|
||||
int arg_marshal = (src >> 24) & 0xff;
|
||||
|
||||
switch (arg_marshal) {
|
||||
case GSHAREDVT_ARG_NONE:
|
||||
@ -66,8 +66,8 @@ mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpoint
|
||||
break;
|
||||
case GSHAREDVT_ARG_BYREF_TO_BYVAL: {
|
||||
/* gsharedvt argument passed by value */
|
||||
int nslots = (src >> 4) & 0xff;
|
||||
int src_slot = src & 0xf;
|
||||
int nslots = (src >> 8) & 0xff;
|
||||
int src_slot = src & 0xff;
|
||||
int j;
|
||||
gpointer *addr = caller [src_slot];
|
||||
|
||||
@ -76,28 +76,28 @@ mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpoint
|
||||
break;
|
||||
}
|
||||
case GSHAREDVT_ARG_BYREF_TO_BYVAL_I1: {
|
||||
int src_slot = src & 0xf;
|
||||
int src_slot = src & 0xff;
|
||||
gpointer *addr = caller [src_slot];
|
||||
|
||||
callee [dst] = GINT_TO_POINTER ((int)*(gint8*)addr);
|
||||
break;
|
||||
}
|
||||
case GSHAREDVT_ARG_BYREF_TO_BYVAL_I2: {
|
||||
int src_slot = src & 0xf;
|
||||
int src_slot = src & 0xff;
|
||||
gpointer *addr = caller [src_slot];
|
||||
|
||||
callee [dst] = GINT_TO_POINTER ((int)*(gint16*)addr);
|
||||
break;
|
||||
}
|
||||
case GSHAREDVT_ARG_BYREF_TO_BYVAL_U1: {
|
||||
int src_slot = src & 0xf;
|
||||
int src_slot = src & 0xff;
|
||||
gpointer *addr = caller [src_slot];
|
||||
|
||||
callee [dst] = GUINT_TO_POINTER ((guint)*(guint8*)addr);
|
||||
break;
|
||||
}
|
||||
case GSHAREDVT_ARG_BYREF_TO_BYVAL_U2: {
|
||||
int src_slot = src & 0xf;
|
||||
int src_slot = src & 0xff;
|
||||
gpointer *addr = caller [src_slot];
|
||||
|
||||
callee [dst] = GUINT_TO_POINTER ((guint)*(guint16*)addr);
|
||||
|
@ -1 +1 @@
|
||||
#define FULL_VERSION "Stable 5.0.0.48/851b6c7"
|
||||
#define FULL_VERSION "Stable 5.0.0.61/4242008"
|
||||
|
BIN
po/mcs/de.gmo
BIN
po/mcs/de.gmo
Binary file not shown.
@ -1 +1 @@
|
||||
5f068b378071d61ca60f10fd4f4604c4bae5bdbc
|
||||
760fdff9f33684cc748d1e946bb6c13a689618e8
|
BIN
po/mcs/es.gmo
BIN
po/mcs/es.gmo
Binary file not shown.
@ -1 +1 @@
|
||||
40663cf47875043c34b953349e194fcf894a95cc
|
||||
1a6e2559d7a80797c4b973e659acc65b68c848ef
|
BIN
po/mcs/ja.gmo
BIN
po/mcs/ja.gmo
Binary file not shown.
@ -1 +1 @@
|
||||
2e03765163e24dbfee9880d67d978f9da4cded26
|
||||
5d060c5c9574e03c012c0535098ff6fda7f95bf8
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: mono 5.0.0\n"
|
||||
"Report-Msgid-Bugs-To: http://www.mono-project.com/Bugs\n"
|
||||
"POT-Creation-Date: 2017-04-11 11:15+0000\n"
|
||||
"POT-Creation-Date: 2017-04-19 15:43+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
BIN
po/mcs/pt_BR.gmo
BIN
po/mcs/pt_BR.gmo
Binary file not shown.
@ -1 +1 @@
|
||||
b0660e81b0e4e4028fcebdc20dd98903b7e86651
|
||||
b85343d1642203f49c23501b87fd68392a48afa0
|
Loading…
x
Reference in New Issue
Block a user