如何签署以编程方式生成的 iOS 配置文件?

How-to sign an iOS configuration profile generated programmatically?

上下文

我有一个 Web 应用程序(前端 JS / 后端 PHP)以编程方式生成一些 MDM iOS configuration profiles (*.mobileconfig)。

网站用户输入一些信息,调用我的 PHP api,我的 PHP 后端 生成一个配置文件 "on-the-fly" 与用户特定的数据,将其保存在服务器上,并且 return 返回生成的配置文件的 URL,因此用户可以单击此 link 并将其安装在其 iOS 设备。

简而言之:此配置文件在其有效负载中仅包含一个 webclip(Safari 快捷方式)。

一切正常,配置文件 link 打开 iOS 设置应用程序,要求用户在其设备上安装此配置文件。

我的问题是这个以编程方式生成的配置文件没有签名。因此,iOS 警告用户 配置文件未签名,他必须执行几个额外的操作来确认配置文件安装。

我希望对生成的配置文件进行签名,以便用户可以更轻松、更快速地安装它们。

问题

  • 可能吗?
  • 如果是,PHP可以吗?
  • 如果是,我该怎么做?

我阅读了一些有关签署配置文件的资源,但我并不了解所有内容,我没有任何关于签署、证书等的技能。

我不太清楚!

感谢任何帮助,提前致谢!

是的,你可以。还有 PHP.

如何?

  1. 将您要签署的配置文件保存到临时文件:

    file_put_contents ($tmp_file_name, $profile_data);

  2. 签署您刚刚创建的文件:

    $data = shell_exec ("openssl smime -sign -in $tmp_file_name {add here another parameters you need...}");

  3. 发送数据给客户端:

    echo $data;

  4. 删除 tmp 文件...

    unlink ($tmp_file_name);

我可以使用 @zvi 答案确认它是否有效。谢谢!

让我提供有关我的实施的更多详细信息以帮助其他人。特别是我对我需要签署哪些文件以及如何获得它们感到困惑。

1.获得证书

我使用了 Let's Encrypt, through ZeroSSL 的免费证书来轻松获取所需的 2 个文件(证书和私钥)。

您需要证明该域是您的(使用 FTP 或 DNS 方法)

我将证书保存为"certificate.crt",将私钥保存为 "private-key.pem"。将它们上传到您的服务器。

2。获取证书授权链文件

如果您只使用上面的 2 个文件,您的个人资料将在 iOS(我正在寻找的绿色复选标记)"verified""verified"

中签名

this page 下载 "Chain of Trust"。

我用了"Let’s Encrypt Authority X3 (IdenTrust cross-signed)"一个,保存到"ca-chain.pem"。将它与另外两个一起上传到您的服务器。

3。创建一个PHP登录方法

为了通过 PHP 脚本对其进行签名,我为此创建了一个方法,采用输入配置文件(未签名)并写入输出配置文件(已签名)。

我使用 the method descibed here 从 PHP 使用 shell_exec[调用 openssl 命令

<?php
function sslSignProfileToFile($inputFile, $outputFile)
{
    $sslPath = '/absolute/path/to/your/cert/files';
    shell_exec("openssl smime -sign -signer ".$sslPath."/certificate.crt -inkey ".$sslPath."/private-key.pem -certfile ".$sslPath."/ca-chain.pem -nodetach -outform der -in ".$inputFile." -out ".$outputFile);
}
?>

4.生成您的个人资料并签名

根据需要生成,然后调用上面的方法制作签名副本。

<?php
sslSignProfileToFile( "/path/to/your/unsigned-profile.mobileconfig", "/path/to/your/signed-profile.mobileconfig");
?>

5.享受吧!

然后就看你的了:

  • 如果你和我一样在AJAX请求中,你可以return回到bodyURL到已签名的配置文件中下载

  • 如果您使用的是经典形式 POST 操作,您可以只执行 header 重定向 like explained here(未经本人测试)

如果只是签名问题,我之前已经回答过一个,见:

/**
 * Sign MobileConfig
 *
 * @return string
 */
function signMobileConfig (
    string $file_full_pathname,
    string $certificate_pathname,
    string $private_key_pathname,
    bool $remove_file = true
) {
    openssl_pkcs7_sign(
        $file_full_pathname,
        $file_full_pathname.'.sig',
        file_get_contents($certificate_pathname),
        file_get_contents($private_key_pathname),
        [], 0
    );

    $signed = file_get_contents($file_full_pathname.'.sig');

    if ($remove_file) {
        unlink($file_full_pathname.'.sig');
        unlink($file_full_pathname);
    }

    $trimmed = preg_replace('/(.+\n)+\n/', '', $signed, 1);
    return base64_decode($trimmed);
}

result of signed config file(<10 声望,点击查看结果)

请随意修改上面的代码以满足您的需求。