|
30 | 30 | #include "stat-util.h" |
31 | 31 | #include "tpm2-util.h" |
32 | 32 | #include "user-util.h" |
| 33 | +#include "varlink.h" |
33 | 34 |
|
34 | 35 | #define PUBLIC_KEY_MAX (UINT32_C(1024) * UINT32_C(1024)) |
35 | 36 |
|
@@ -1534,3 +1535,130 @@ int decrypt_credential_and_warn(const char *validate_name, usec_t validate_times |
1534 | 1535 | } |
1535 | 1536 |
|
1536 | 1537 | #endif |
| 1538 | + |
| 1539 | +int ipc_encrypt_credential(const char *name, usec_t timestamp, usec_t not_after, uid_t uid, const struct iovec *input, CredentialFlags flags, struct iovec *ret) { |
| 1540 | + _cleanup_(varlink_unrefp) Varlink *vl = NULL; |
| 1541 | + int r; |
| 1542 | + |
| 1543 | + assert(input && iovec_is_valid(input)); |
| 1544 | + assert(ret); |
| 1545 | + |
| 1546 | + r = varlink_connect_address(&vl, "/run/systemd/io.systemd.Credentials"); |
| 1547 | + if (r < 0) |
| 1548 | + return log_error_errno(r, "Failed to connect to io.systemd.Credentials: %m"); |
| 1549 | + |
| 1550 | + /* Mark anything we get from the service as sensitive, given that it might use a NULL cypher, at least in theory */ |
| 1551 | + r = varlink_set_input_sensitive(vl); |
| 1552 | + if (r < 0) |
| 1553 | + return log_error_errno(r, "Failed to enable sensitive Varlink input: %m"); |
| 1554 | + |
| 1555 | + /* Create the input data blob object separately, so that we can mark it as sensitive */ |
| 1556 | + _cleanup_(json_variant_unrefp) JsonVariant *jinput = NULL; |
| 1557 | + r = json_build(&jinput, JSON_BUILD_IOVEC_BASE64(input)); |
| 1558 | + if (r < 0) |
| 1559 | + return log_error_errno(r, "Failed to create input object: %m"); |
| 1560 | + |
| 1561 | + json_variant_sensitive(jinput); |
| 1562 | + |
| 1563 | + _cleanup_(json_variant_unrefp) JsonVariant *reply = NULL; |
| 1564 | + const char *error_id = NULL; |
| 1565 | + r = varlink_callb(vl, |
| 1566 | + "io.systemd.Credentials.Encrypt", |
| 1567 | + &reply, |
| 1568 | + &error_id, |
| 1569 | + JSON_BUILD_OBJECT( |
| 1570 | + JSON_BUILD_PAIR_CONDITION(name, "name", JSON_BUILD_STRING(name)), |
| 1571 | + JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(jinput)), |
| 1572 | + JSON_BUILD_PAIR_CONDITION(timestamp != USEC_INFINITY, "timestamp", JSON_BUILD_UNSIGNED(timestamp)), |
| 1573 | + JSON_BUILD_PAIR_CONDITION(not_after != USEC_INFINITY, "notAfter", JSON_BUILD_UNSIGNED(not_after)), |
| 1574 | + JSON_BUILD_PAIR_CONDITION(!FLAGS_SET(flags, CREDENTIAL_ANY_SCOPE), "scope", JSON_BUILD_STRING(uid_is_valid(uid) ? "user" : "system")), |
| 1575 | + JSON_BUILD_PAIR_CONDITION(uid_is_valid(uid), "uid", JSON_BUILD_UNSIGNED(uid)))); |
| 1576 | + if (r < 0) |
| 1577 | + return log_error_errno(r, "Failed to call Encrypt() varlink call."); |
| 1578 | + if (!isempty(error_id)) { |
| 1579 | + if (streq(error_id, "io.systemd.Credentials.NoSuchUser")) |
| 1580 | + return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "No such user."); |
| 1581 | + |
| 1582 | + return log_error_errno(varlink_error_to_errno(error_id, reply), "Failed to encrypt: %s", error_id); |
| 1583 | + } |
| 1584 | + |
| 1585 | + r = json_dispatch( |
| 1586 | + reply, |
| 1587 | + (const JsonDispatch[]) { |
| 1588 | + { "blob", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, PTR_TO_SIZE(ret), JSON_MANDATORY }, |
| 1589 | + {}, |
| 1590 | + }, |
| 1591 | + JSON_LOG|JSON_ALLOW_EXTENSIONS, |
| 1592 | + /* userdata= */ NULL); |
| 1593 | + if (r < 0) |
| 1594 | + return r; |
| 1595 | + |
| 1596 | + return 0; |
| 1597 | +} |
| 1598 | + |
| 1599 | +int ipc_decrypt_credential(const char *validate_name, usec_t validate_timestamp, uid_t uid, const struct iovec *input, CredentialFlags flags, struct iovec *ret) { |
| 1600 | + _cleanup_(varlink_unrefp) Varlink *vl = NULL; |
| 1601 | + int r; |
| 1602 | + |
| 1603 | + assert(input && iovec_is_valid(input)); |
| 1604 | + assert(ret); |
| 1605 | + |
| 1606 | + r = varlink_connect_address(&vl, "/run/systemd/io.systemd.Credentials"); |
| 1607 | + if (r < 0) |
| 1608 | + return log_error_errno(r, "Failed to connect to io.systemd.Credentials: %m"); |
| 1609 | + |
| 1610 | + r = varlink_set_input_sensitive(vl); |
| 1611 | + if (r < 0) |
| 1612 | + return log_error_errno(r, "Failed to enable sensitive Varlink input: %m"); |
| 1613 | + |
| 1614 | + /* Create the input data blob object separately, so that we can mark it as sensitive (it's supposed |
| 1615 | + * to be encrypted, but who knows maybe it uses the NULL cypher). */ |
| 1616 | + _cleanup_(json_variant_unrefp) JsonVariant *jinput = NULL; |
| 1617 | + r = json_build(&jinput, JSON_BUILD_IOVEC_BASE64(input)); |
| 1618 | + if (r < 0) |
| 1619 | + return log_error_errno(r, "Failed to create input object: %m"); |
| 1620 | + |
| 1621 | + json_variant_sensitive(jinput); |
| 1622 | + |
| 1623 | + _cleanup_(json_variant_unrefp) JsonVariant *reply = NULL; |
| 1624 | + const char *error_id = NULL; |
| 1625 | + r = varlink_callb(vl, |
| 1626 | + "io.systemd.Credentials.Decrypt", |
| 1627 | + &reply, |
| 1628 | + &error_id, |
| 1629 | + JSON_BUILD_OBJECT( |
| 1630 | + JSON_BUILD_PAIR_CONDITION(validate_name, "name", JSON_BUILD_STRING(validate_name)), |
| 1631 | + JSON_BUILD_PAIR("blob", JSON_BUILD_VARIANT(jinput)), |
| 1632 | + JSON_BUILD_PAIR_CONDITION(validate_timestamp != USEC_INFINITY, "timestamp", JSON_BUILD_UNSIGNED(validate_timestamp)), |
| 1633 | + JSON_BUILD_PAIR_CONDITION(!FLAGS_SET(flags, CREDENTIAL_ANY_SCOPE), "scope", JSON_BUILD_STRING(uid_is_valid(uid) ? "user" : "system")), |
| 1634 | + JSON_BUILD_PAIR_CONDITION(uid_is_valid(uid), "uid", JSON_BUILD_UNSIGNED(uid)))); |
| 1635 | + if (r < 0) |
| 1636 | + return log_error_errno(r, "Failed to call Decrypt() varlink call."); |
| 1637 | + if (!isempty(error_id)) { |
| 1638 | + if (streq(error_id, "io.systemd.Credentials.BadFormat")) |
| 1639 | + return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Bad credential format."); |
| 1640 | + if (streq(error_id, "io.systemd.Credentials.NameMismatch")) |
| 1641 | + return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Name in credential doesn't match expectations."); |
| 1642 | + if (streq(error_id, "io.systemd.Credentials.TimeMismatch")) |
| 1643 | + return log_error_errno(SYNTHETIC_ERRNO(ESTALE), "Outside of credential validity time window."); |
| 1644 | + if (streq(error_id, "io.systemd.Credentials.NoSuchUser")) |
| 1645 | + return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "No such user."); |
| 1646 | + if (streq(error_id, "io.systemd.Credentials.BadScope")) |
| 1647 | + return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Scope mismtach."); |
| 1648 | + |
| 1649 | + return log_error_errno(varlink_error_to_errno(error_id, reply), "Failed to decrypt: %s", error_id); |
| 1650 | + } |
| 1651 | + |
| 1652 | + r = json_dispatch( |
| 1653 | + reply, |
| 1654 | + (const JsonDispatch[]) { |
| 1655 | + { "data", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, PTR_TO_SIZE(ret), JSON_MANDATORY }, |
| 1656 | + {}, |
| 1657 | + }, |
| 1658 | + JSON_LOG|JSON_ALLOW_EXTENSIONS, |
| 1659 | + /* userdata= */ NULL); |
| 1660 | + if (r < 0) |
| 1661 | + return r; |
| 1662 | + |
| 1663 | + return 0; |
| 1664 | +} |
0 commit comments