Exemple #1
0
def _load_certificate_data(certtype, buffer, result_typeid):
    """
    Load a certificate with the supplied type and data.

    @param certtype: ignored
    @type certtype: -
    @param buffer: name of the KeyChain item to lookup
    @type buffer: L{str}
    @param result_typeid: The type to return (certificate or key)
    @type result_typeid: L{ffi.CFTypeID}

    @return: the certificate
    @rtype: L{X509}
    """

    # First try to get the identity from the KeyChain
    data = CFDataRef.fromString(buffer)
    results = ffi.new("CFArrayRef *")
    err = security.SecItemImport(data.ref(), ffi.NULL, ffi.NULL, ffi.NULL, 0,
                                 ffi.NULL, ffi.NULL, results)
    if err != 0:
        raise Error("Could not load certificate data")

    results = CFArrayRef(results[0]).toList()

    # Try to find a SecCertificateRef
    for result in results:
        if result.instanceTypeId() == result_typeid:
            return result
    else:
        raise Error("No certificate in data")
Exemple #2
0
def check_keychain_identity(identity, allowInteraction=False):
    """
    Verify that the Keychain identity exists and that the private key is accessible.

    @param identity: identity value to match
    @type identity: L{str}

    @return: empty L{str} if OK, error message if not
    @rtype: L{str}
    """

    # Always turn off user interaction
    security.SecKeychainSetUserInteractionAllowed(allowInteraction)

    try:
        secidentity = load_keychain_identity(identity)
    except Error:
        return "Unable to load Keychain identity: {}".format(identity)
    pkey = ffi.new("SecKeyRef *")
    err = security.SecIdentityCopyPrivateKey(secidentity.ref(), pkey)
    if err != 0:
        return "Unable to load private key for Keychain identity: {}".format(
            identity)
    pkey = CFObjectRef(pkey[0])

    # Try to sign some data with the pkey to check we have access
    error = ffi.new("CFErrorRef *")
    signer = security.SecSignTransformCreate(pkey.ref(), error)
    if error[0] != ffi.NULL:
        cferror = CFErrorRef(error[0])
        return "Unable to use private key for Keychain identity: {} - {}".format(
            identity, cferror.description())
    signer = CFObjectRef(signer)

    signMe = CFDataRef.fromString("sign me")
    security.SecTransformSetAttribute(signer.ref(),
                                      security.kSecTransformInputAttributeName,
                                      signMe.ref(), error)
    if error[0] != ffi.NULL:
        cferror = CFErrorRef(error[0])
        return "Unable to use private key for Keychain identity: {} - {}".format(
            identity, cferror.description())

    signature = security.SecTransformExecute(signer.ref(), error)
    if error[0] != ffi.NULL or signature == ffi.NULL:
        cferror = CFErrorRef(error[0])
        return "Unable to use private key for Keychain identity: {} - {}".format(
            identity, cferror.description())
    signature = CFObjectRef(signature)

    return ""
Exemple #3
0
    def test_cms_sign_verify_ok(self):
        """
        Use the simple encode.
        """

        # Sign some data
        sign = "Something to be signed"
        result = ffi.new("CFDataRef *")
        signer = load_keychain_identity("org.calendarserver.test")
        error = cms.CMSEncodeContent(
            signer.ref(),
            ffi.NULL,
            ffi.NULL,
            False,
            cms.kCMSAttrNone,
            sign,
            len(sign),
            result,
        )
        self.assertEqual(error, 0)
        result = CFDataRef(result[0])
        self.assertNotEqual(result.count(), 0)

        # Now verify the result
        decoder = ffi.new("CMSDecoderRef *")
        error = cms.CMSDecoderCreate(decoder)
        self.assertEqual(error, 0)
        decoder = CFObjectRef(decoder[0])

        error = cms.CMSDecoderUpdateMessage(decoder.ref(), result.toString(), result.count())
        self.assertEqual(error, 0)

        error = cms.CMSDecoderFinalizeMessage(decoder.ref())
        self.assertEqual(error, 0)

        number = ffi.new("size_t *")
        error = cms.CMSDecoderGetNumSigners(decoder.ref(), number)
        self.assertEqual(error, 0)
        self.assertEqual(number[0], 1)

        encrypted = ffi.new("Boolean *")
        error = cms.CMSDecoderIsContentEncrypted(decoder.ref(), encrypted)
        self.assertEqual(error, 0)
        self.assertEqual(encrypted[0], False)

        policy = cms.SecPolicyCreateBasicX509()
        policy = CFObjectRef(policy)
        status = ffi.new("CMSSignerStatus *")
        verify_result = ffi.new("OSStatus *")
        error = cms.CMSDecoderCopySignerStatus(
            decoder.ref(),
            0,
            policy.ref(),
            True,
            status,
            ffi.NULL,
            verify_result,
        )
        self.assertEqual(error, 0)
        self.assertEqual(status[0], cms.kCMSSignerValid)
        self.assertEqual(verify_result[0], 0)

        result = ffi.new("CFDataRef *")
        error = cms.CMSDecoderCopyContent(decoder.ref(), result)
        self.assertEqual(error, 0)
        result = CFDataRef(result[0])
        self.assertEqual(result.toString(), sign)
Exemple #4
0
def convertStringsFile(src, dest):

    dir = os.path.dirname(dest)

    if not os.path.exists(dir):
        try:
            os.makedirs(dir)
        except OSError:
            # can't create directory to hold .po file
            return

    # Parse the binary plist .strings file:
    with open(src) as f:
        data = f.read()
    data = CFDataRef.fromString(data)
    try:
        parsed = CFPropertyListRef.createFromData(data)
        strings = parsed.toDict()
    except CFError as error:
        raise ParseError(error)

    # The format of GNUtext MO files is described here:
    # http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html

    originals = strings.keys()
    originals.sort()

    descriptors = []
    keys = ''
    values = ''

    for original in originals:
        translation = strings[original]

        if isinstance(original, unicode):
            original = original.encode("UTF-8")
        if isinstance(translation, unicode):
            translation = translation.encode("UTF-8")

        descriptors.append(
            (len(keys), len(original), len(values), len(translation)))
        keys += original + '\0'  # <NUL> terminated
        values += translation + '\0'

    # The header is 28 bytes, each descriptor is 8 bytes, with two descriptors
    # per string (one pointing at original, one pointing at translation)
    keysOffset = 28 + len(originals) * 2 * 8
    valuesOffset = keysOffset + len(keys)

    keyDescriptors = []
    valueDescriptors = []
    for origOffset, origLen, transOffset, transLen in descriptors:
        keyDescriptors.append(origLen)
        keyDescriptors.append(keysOffset + origOffset)
        valueDescriptors.append(transLen)
        valueDescriptors.append(valuesOffset + transOffset)

    result = struct.pack(
        "Iiiiiii",
        0x950412DEL,  # magic number
        0,  # file format revision
        len(originals),  # number of strings
        28,  # offset of table with original strings
        28 + len(originals) * 8,  # offset of table with translation strings
        0,  # size of hashing table
        0  # offset of hashing table
    )
    result += array.array("i", keyDescriptors).tostring()
    result += array.array("i", valueDescriptors).tostring()
    result += keys
    result += values

    with open(dest, "wb") as outFile:
        outFile.write(result)